From 6b1149d5ec3ce989c8a4b78f000c533bdcdbbbc0 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 24 Sep 2015 17:02:07 +0300 Subject: [PATCH 01/14] use the infcx tables to check if a closure is Copy Fixes #28550 --- src/librustc/middle/infer/mod.rs | 9 ++++++++- src/test/run-pass/issue-28550.rs | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-28550.rs diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 917727907ba88..e21e49ac5c8d9 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -1389,9 +1389,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.resolve_type_vars_or_error(&ty) } + pub fn tables_are_tcx_tables(&self) -> bool { + let tables: &RefCell = &self.tables; + let tcx_tables: &RefCell = &self.tcx.tables; + tables as *const _ == tcx_tables as *const _ + } + pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool { let ty = self.resolve_type_vars_if_possible(&ty); - if ty.needs_infer() { + if ty.needs_infer() || + (ty.has_closure_types() && !self.tables_are_tcx_tables()) { // this can get called from typeck (by euv), and moves_by_default // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other diff --git a/src/test/run-pass/issue-28550.rs b/src/test/run-pass/issue-28550.rs new file mode 100644 index 0000000000000..f44a535e8176e --- /dev/null +++ b/src/test/run-pass/issue-28550.rs @@ -0,0 +1,25 @@ +// 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 AT,T>(F::Output); +struct BT,T>(A); + +// Removing Option causes it to compile. +fn fooT>(f: F) -> Option> { + Some(B(A(f()))) +} + +fn main() { + let v = (|| foo(||4))(); + match v { + Some(B(A(4))) => {}, + _ => unreachable!() + } +} From 24b5d3afd75a6cdbaca1dc488d43b90f159108cb Mon Sep 17 00:00:00 2001 From: Simon Mazur Date: Thu, 24 Sep 2015 02:03:47 +0300 Subject: [PATCH 02/14] Improve speed of `fmt::Debug` for `str` and `char` fixes #26920 --- src/libcore/char.rs | 10 ++++++++++ src/libcore/fmt/mod.rs | 22 +++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index dfcbfd476bc3f..a697c8c320e30 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -147,6 +147,7 @@ pub trait CharExt { fn to_digit(self, radix: u32) -> Option; fn escape_unicode(self) -> EscapeUnicode; fn escape_default(self) -> EscapeDefault; + fn needs_escape_default(self) -> bool; fn len_utf8(self) -> usize; fn len_utf16(self) -> usize; fn encode_utf8(self, dst: &mut [u8]) -> Option; @@ -194,6 +195,15 @@ impl CharExt for char { EscapeDefault { state: init_state } } + #[inline] + fn needs_escape_default(self) -> bool { + match self { + '\\' | '\'' | '"' => true, + '\x20' ... '\x7e' => false, + _ => true + } + } + #[inline] fn len_utf8(self) -> usize { let code = self as u32; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index db7e6d3006f3f..cbcb3026a8e4c 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1310,11 +1310,20 @@ impl Display for bool { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for str { fn fmt(&self, f: &mut Formatter) -> Result { - try!(write!(f, "\"")); - for c in self.chars().flat_map(|c| c.escape_default()) { - try!(f.write_char(c)) + try!(f.write_char('"')); + let mut from = 0; + for (i, c) in self.char_indices() { + // If char needs escaping, flush backlog so far and write, else skip + if c.needs_escape_default() { + try!(f.write_str(&self[from..i])); + for e in c.escape_default() { + try!(f.write_char(e)); + } + from = i + c.len_utf8(); + } } - write!(f, "\"") + try!(f.write_str(&self[from..])); + f.write_char('"') } } @@ -1328,12 +1337,11 @@ impl Display for str { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for char { fn fmt(&self, f: &mut Formatter) -> Result { - use char::CharExt; - try!(write!(f, "'")); + try!(f.write_char('\'')); for c in self.escape_default() { try!(f.write_char(c)) } - write!(f, "'") + f.write_char('\'') } } From 025ca11ab909a2f2eda4ae8ccb891acf83b296f3 Mon Sep 17 00:00:00 2001 From: Simon Mazur Date: Tue, 29 Sep 2015 15:53:58 +0300 Subject: [PATCH 03/14] Add `fmt::Debug` string escape tests --- src/test/run-pass/ifmt.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index c8adb6ccc0ab8..2cc033b8a46e1 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -74,6 +74,10 @@ pub fn main() { t!(format!("{:?}", 10_usize), "10"); t!(format!("{:?}", "true"), "\"true\""); t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), + r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); + t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"), + r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#); t!(format!("{:o}", 10_usize), "12"); t!(format!("{:x}", 10_usize), "a"); t!(format!("{:X}", 10_usize), "A"); From d2d08721bebe5c200a1db1173a2e5f109393c725 Mon Sep 17 00:00:00 2001 From: Simon Mazur Date: Tue, 29 Sep 2015 21:25:40 +0300 Subject: [PATCH 04/14] Implement `size_hint` for `EscapeDefault` --- src/libcore/char.rs | 23 ++++++++++------------- src/libcore/fmt/mod.rs | 7 ++++--- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index a697c8c320e30..8d1af46691c70 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -147,7 +147,6 @@ pub trait CharExt { fn to_digit(self, radix: u32) -> Option; fn escape_unicode(self) -> EscapeUnicode; fn escape_default(self) -> EscapeDefault; - fn needs_escape_default(self) -> bool; fn len_utf8(self) -> usize; fn len_utf16(self) -> usize; fn encode_utf8(self, dst: &mut [u8]) -> Option; @@ -186,24 +185,13 @@ impl CharExt for char { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), - '\\' => EscapeDefaultState::Backslash('\\'), - '\'' => EscapeDefaultState::Backslash('\''), - '"' => EscapeDefaultState::Backslash('"'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), '\x20' ... '\x7e' => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; EscapeDefault { state: init_state } } - #[inline] - fn needs_escape_default(self) -> bool { - match self { - '\\' | '\'' | '"' => true, - '\x20' ... '\x7e' => false, - _ => true - } - } - #[inline] fn len_utf8(self) -> usize { let code = self as u32; @@ -390,4 +378,13 @@ impl Iterator for EscapeDefault { EscapeDefaultState::Unicode(ref mut iter) => iter.next() } } + + fn size_hint(&self) -> (usize, Option) { + match self.state { + EscapeDefaultState::Char(_) => (1, Some(1)), + EscapeDefaultState::Backslash(_) => (2, Some(2)), + EscapeDefaultState::Unicode(_) => (0, Some(10)), + _ => (0, Some(0)) + } + } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index cbcb3026a8e4c..88b3963df8d9b 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1313,11 +1313,12 @@ impl Debug for str { try!(f.write_char('"')); let mut from = 0; for (i, c) in self.char_indices() { + let esc = c.escape_default(); // If char needs escaping, flush backlog so far and write, else skip - if c.needs_escape_default() { + if esc.size_hint().0 != 1 { try!(f.write_str(&self[from..i])); - for e in c.escape_default() { - try!(f.write_char(e)); + for c in esc { + try!(f.write_char(c)); } from = i + c.len_utf8(); } From 8c963c07a8e56320d33681050f94b467cfcc6251 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 30 Sep 2015 10:08:37 -0700 Subject: [PATCH 05/14] rustc: Support output filenames for each emit type Currently the compiler supports the ability to emit multiple output types as part of one compilation (e.g. asm, LLVM IR, bytecode, link, dep-info, etc). It does not, however, support the ability to customize the output filename for each of these output types. The `-o` flag is ignored if multiple emit types are specified (and the compiler emits a warning about this). Normally this doesn't matter too much, but in the case of `dep-info` it can lead to a number of problems (e.g. see #28716). By allowing customization of the output filename for each emit type we're able to solve the problems in that issue. This commit adds support for the `--emit` option to the compiler to look like: rustc foo.rs --emit dep-info=.deps/foo.d,link This indicates that the `dep-info` output type will be placed at `.deps/foo.d` and the `link` output type will otherwise be determined via the `--out-dir` and `-o` flags. Closes #28716 --- man/rustc.1 | 7 +- src/librustc/session/config.rs | 76 +++++++--------- src/librustc_driver/driver.rs | 52 +++++------ src/librustc_driver/lib.rs | 4 +- src/librustc_trans/back/link.rs | 18 ++-- src/librustc_trans/back/write.rs | 90 +++++++++---------- src/librustdoc/test.rs | 6 +- src/test/run-make/issue-19371/foo.rs | 6 +- .../output-type-permutations/Makefile | 48 ++++++++-- 9 files changed, 165 insertions(+), 142 deletions(-) diff --git a/man/rustc.1 b/man/rustc.1 index 3ac79ecae64e5..56e3fe0515eb9 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -53,7 +53,9 @@ Comma separated list of types of crates for the compiler to emit. Specify the name of the crate being built. .TP \fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info] -Configure the output that \fBrustc\fR will produce. +Configure the output that \fBrustc\fR will produce. Each option may also be of +the form KIND=PATH to specify the explicit output location for that particular +emission kind. .TP \fB\-\-print\fR [crate\-name|file\-names|sysroot] Comma separated list of compiler information to print on stdout. @@ -66,7 +68,8 @@ Equivalent to \fI\-C\ opt\-level=2\fR. .TP \fB\-o\fR \fIFILENAME\fR Write output to \fIFILENAME\fR. -Ignored if multiple \fI\-\-emit\fR outputs are specified. +Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an +explicit path otherwise. .TP \fB\-\-out\-dir\fR \fIDIR\fR Write output to compiler\[hy]chosen filename in \fIDIR\fR. diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index dcc4ca137ead9..0739420ea4d68 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -15,7 +15,6 @@ pub use self::EntryFnType::*; pub use self::CrateType::*; pub use self::Passes::*; pub use self::OptLevel::*; -pub use self::OutputType::*; pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; @@ -62,14 +61,14 @@ pub enum DebugInfoLevel { FullDebugInfo, } -#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum OutputType { - OutputTypeBitcode, - OutputTypeAssembly, - OutputTypeLlvmAssembly, - OutputTypeObject, - OutputTypeExe, - OutputTypeDepInfo, + Bitcode, + Assembly, + LlvmAssembly, + Object, + Exe, + DepInfo, } #[derive(Clone)] @@ -85,7 +84,7 @@ pub struct Options { pub lint_opts: Vec<(String, lint::Level)>, pub lint_cap: Option, pub describe_lints: bool, - pub output_types: Vec, + pub output_types: HashMap>, // This was mutable for rustpkg, which updates search paths based on the // parsed code. It remains mutable in case its replacements wants to use // this. @@ -105,8 +104,6 @@ pub struct Options { pub always_build_mir: bool, pub no_analysis: bool, pub debugging_opts: DebuggingOptions, - /// Whether to write dependency files. It's (enabled, optional filename). - pub write_dependency_info: (bool, Option), pub prints: Vec, pub cg: CodegenOptions, pub color: ColorConfig, @@ -151,26 +148,25 @@ pub struct OutputFilenames { pub out_filestem: String, pub single_output_file: Option, pub extra: String, + pub outputs: HashMap>, } impl OutputFilenames { pub fn path(&self, flavor: OutputType) -> PathBuf { - match self.single_output_file { - Some(ref path) => return path.clone(), - None => {} - } - self.temp_path(flavor) + self.outputs.get(&flavor).and_then(|p| p.to_owned()) + .or_else(|| self.single_output_file.clone()) + .unwrap_or_else(|| self.temp_path(flavor)) } pub fn temp_path(&self, flavor: OutputType) -> PathBuf { let base = self.out_directory.join(&self.filestem()); match flavor { - OutputTypeBitcode => base.with_extension("bc"), - OutputTypeAssembly => base.with_extension("s"), - OutputTypeLlvmAssembly => base.with_extension("ll"), - OutputTypeObject => base.with_extension("o"), - OutputTypeDepInfo => base.with_extension("d"), - OutputTypeExe => base, + OutputType::Bitcode => base.with_extension("bc"), + OutputType::Assembly => base.with_extension("s"), + OutputType::LlvmAssembly => base.with_extension("ll"), + OutputType::Object => base.with_extension("o"), + OutputType::DepInfo => base.with_extension("d"), + OutputType::Exe => base, } } @@ -206,7 +202,7 @@ pub fn basic_options() -> Options { lint_opts: Vec::new(), lint_cap: None, describe_lints: false, - output_types: Vec::new(), + output_types: HashMap::new(), search_paths: SearchPaths::new(), maybe_sysroot: None, target_triple: host_triple().to_string(), @@ -218,7 +214,6 @@ pub fn basic_options() -> Options { always_build_mir: false, no_analysis: false, debugging_opts: basic_debugging_options(), - write_dependency_info: (false, None), prints: Vec::new(), cg: basic_codegen_options(), color: Auto, @@ -907,31 +902,30 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { unsafe { llvm::LLVMSetDebug(1); } } - let mut output_types = Vec::new(); + let mut output_types = HashMap::new(); if !debugging_opts.parse_only && !no_trans { - let unparsed_output_types = matches.opt_strs("emit"); - for unparsed_output_type in &unparsed_output_types { - for part in unparsed_output_type.split(',') { - let output_type = match part { - "asm" => OutputTypeAssembly, - "llvm-ir" => OutputTypeLlvmAssembly, - "llvm-bc" => OutputTypeBitcode, - "obj" => OutputTypeObject, - "link" => OutputTypeExe, - "dep-info" => OutputTypeDepInfo, - _ => { + for list in matches.opt_strs("emit") { + for output_type in list.split(',') { + let mut parts = output_type.splitn(2, '='); + let output_type = match parts.next().unwrap() { + "asm" => OutputType::Assembly, + "llvm-ir" => OutputType::LlvmAssembly, + "llvm-bc" => OutputType::Bitcode, + "obj" => OutputType::Object, + "link" => OutputType::Exe, + "dep-info" => OutputType::DepInfo, + part => { early_error(color, &format!("unknown emission type: `{}`", part)) } }; - output_types.push(output_type) + let path = parts.next().map(PathBuf::from); + output_types.insert(output_type, path); } } }; - output_types.sort(); - output_types.dedup(); if output_types.is_empty() { - output_types.push(OutputTypeExe); + output_types.insert(OutputType::Exe, None); } let cg = build_codegen_options(matches, color); @@ -1004,7 +998,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let cfg = parse_cfgspecs(matches.opt_strs("cfg")); let test = matches.opt_present("test"); - let write_dependency_info = (output_types.contains(&OutputTypeDepInfo), None); let prints = matches.opt_strs("print").into_iter().map(|s| { match &*s { @@ -1059,7 +1052,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { always_build_mir: always_build_mir, no_analysis: no_analysis, debugging_opts: debugging_opts, - write_dependency_info: write_dependency_info, prints: prints, cg: cg, color: color, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ce04a5befd939..e2835ae8f0d6f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -12,7 +12,7 @@ use rustc::front; use rustc::front::map as hir_map; use rustc_mir as mir; use rustc::session::Session; -use rustc::session::config::{self, Input, OutputFilenames}; +use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::metadata; @@ -36,6 +36,7 @@ use super::Compilation; use serialize::json; +use std::collections::HashMap; use std::env; use std::ffi::{OsString, OsStr}; use std::fs; @@ -117,7 +118,7 @@ pub fn compile_input(sess: Session, let arenas = ty::CtxtArenas::new(); let ast_map = make_map(&sess, &mut hir_forest); - write_out_deps(&sess, input, &outputs, &id[..]); + write_out_deps(&sess, &outputs, &id); controller_entry_point!(after_write_deps, sess, @@ -807,16 +808,16 @@ pub fn phase_5_run_llvm_passes(sess: &Session, trans: &trans::CrateTranslation, outputs: &OutputFilenames) { if sess.opts.cg.no_integrated_as { - let output_type = config::OutputTypeAssembly; - + let mut map = HashMap::new(); + map.insert(OutputType::Assembly, None); time(sess.time_passes(), "LLVM passes", || - write::run_passes(sess, trans, &[output_type], outputs)); + write::run_passes(sess, trans, &map, outputs)); write::run_assembler(sess, outputs); // Remove assembly source, unless --save-temps was specified if !sess.opts.cg.save_temps { - fs::remove_file(&outputs.temp_path(config::OutputTypeAssembly)).unwrap(); + fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap(); } } else { time(sess.time_passes(), "LLVM passes", || @@ -847,16 +848,12 @@ fn escape_dep_filename(filename: &str) -> String { filename.replace(" ", "\\ ") } -fn write_out_deps(sess: &Session, - input: &Input, - outputs: &OutputFilenames, - id: &str) { - +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) { let mut out_filenames = Vec::new(); - for output_type in &sess.opts.output_types { + for output_type in sess.opts.output_types.keys() { let file = outputs.path(*output_type); match *output_type { - config::OutputTypeExe => { + OutputType::Exe => { for output in sess.crate_types.borrow().iter() { let p = link::filename_for_input(sess, *output, id, outputs); @@ -867,23 +864,11 @@ fn write_out_deps(sess: &Session, } } - // Write out dependency rules to the dep-info file if requested with - // --dep-info - let deps_filename = match sess.opts.write_dependency_info { - // Use filename from --dep-file argument if given - (true, Some(ref filename)) => filename.clone(), - // Use default filename: crate source filename with extension replaced - // by ".d" - (true, None) => match *input { - Input::File(..) => outputs.with_extension("d"), - Input::Str(..) => { - sess.warn("can not write --dep-info without a filename \ - when compiling stdin."); - return - }, - }, - _ => return, - }; + // Write out dependency rules to the dep-info file if requested + if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { + return + } + let deps_filename = outputs.path(OutputType::DepInfo); let result = (|| -> io::Result<()> { // Build a list of files used to compile the output and @@ -1012,11 +997,15 @@ pub fn build_output_filenames(input: &Input, out_filestem: stem, single_output_file: None, extra: sess.opts.cg.extra_filename.clone(), + outputs: sess.opts.output_types.clone(), } } Some(ref out_file) => { - let ofile = if sess.opts.output_types.len() > 1 { + let unnamed_output_types = sess.opts.output_types.values() + .filter(|a| a.is_none()) + .count(); + let ofile = if unnamed_output_types > 1 { sess.warn("ignoring specified output filename because multiple \ outputs were requested"); None @@ -1035,6 +1024,7 @@ pub fn build_output_filenames(input: &Input, .to_str().unwrap().to_string(), single_output_file: ofile, extra: sess.opts.cg.extra_filename.clone(), + outputs: sess.opts.output_types.clone(), } } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7d9c74fe48702..d5644d49e1ea4 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -63,7 +63,7 @@ use rustc_resolve as resolve; use rustc_trans::back::link; use rustc_trans::save; use rustc::session::{config, Session, build_session}; -use rustc::session::config::{Input, PrintRequest}; +use rustc::session::config::{Input, PrintRequest, OutputType}; use rustc::lint::Lint; use rustc::lint; use rustc::metadata; @@ -382,7 +382,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_analysis.stop = Compilation::Stop; } - if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) { + if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) { control.after_llvm.stop = Compilation::Stop; } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 4e493e6779c66..1590d20b09e7c 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -16,7 +16,7 @@ use super::msvc; use super::svh::Svh; use session::config; use session::config::NoDebugInfo; -use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; +use session::config::{OutputFilenames, Input, OutputType}; use session::search_paths::PathKind; use session::Session; use metadata::common::LinkMeta; @@ -486,7 +486,7 @@ pub fn filename_for_input(sess: &Session, } config::CrateTypeExecutable => { let suffix = &sess.target.target.options.exe_suffix; - let out_filename = outputs.path(OutputTypeExe); + let out_filename = outputs.path(OutputType::Exe); if suffix.is_empty() { out_filename.to_path_buf() } else { @@ -527,10 +527,12 @@ fn link_binary_output(sess: &Session, outputs: &OutputFilenames, crate_name: &str) -> PathBuf { let objects = object_filenames(sess, outputs); - let out_filename = match outputs.single_output_file { - Some(ref file) => file.clone(), - None => filename_for_input(sess, crate_type, crate_name, outputs), - }; + let default_filename = filename_for_input(sess, crate_type, crate_name, + outputs); + let out_filename = outputs.outputs.get(&OutputType::Exe) + .and_then(|s| s.to_owned()) + .or_else(|| outputs.single_output_file.clone()) + .unwrap_or(default_filename); // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers // check this already -- however, the Linux linker will happily overwrite a @@ -571,7 +573,7 @@ fn link_binary_output(sess: &Session, fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec { (0..sess.opts.cg.codegen_units).map(|i| { let ext = format!("{}.o", i); - outputs.temp_path(OutputTypeObject).with_extension(&ext) + outputs.temp_path(OutputType::Object).with_extension(&ext) }).collect() } @@ -718,7 +720,7 @@ fn link_rlib<'a>(sess: &'a Session, // See the bottom of back::write::run_passes for an explanation // of when we do and don't keep .0.bc files around. let user_wants_numbered_bitcode = - sess.opts.output_types.contains(&OutputTypeBitcode) && + sess.opts.output_types.contains_key(&OutputType::Bitcode) && sess.opts.cg.codegen_units > 1; if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode { remove(sess, &bc_filename); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 94e2891f40fa0..1fbbf82ba38e4 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -12,7 +12,7 @@ use back::lto; use back::link::{get_linker, remove}; use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; -use session::config; +use session::config::{self, OutputType}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; use llvm::SMDiagnosticRef; @@ -23,9 +23,10 @@ use syntax::codemap; use syntax::diagnostic; use syntax::diagnostic::{Emitter, Handler, Level}; +use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::ptr; use std::str; use std::sync::{Arc, Mutex}; @@ -33,15 +34,6 @@ use std::sync::mpsc::channel; use std::thread; use libc::{self, c_uint, c_int, c_void}; -#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] -pub enum OutputType { - OutputTypeBitcode, - OutputTypeAssembly, - OutputTypeLlvmAssembly, - OutputTypeObject, - OutputTypeExe, -} - pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! { unsafe { let cstr = llvm::LLVMRustGetLastError(); @@ -571,7 +563,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, pub fn run_passes(sess: &Session, trans: &CrateTranslation, - output_types: &[config::OutputType], + output_types: &HashMap>, crate_output: &OutputFilenames) { // It's possible that we have `codegen_units > 1` but only one item in // `trans.modules`. We could theoretically proceed and do LTO in that @@ -611,32 +603,32 @@ pub fn run_passes(sess: &Session, // archive in order to allow LTO against it. let needs_crate_bitcode = sess.crate_types.borrow().contains(&config::CrateTypeRlib) && - sess.opts.output_types.contains(&config::OutputTypeExe); + sess.opts.output_types.contains_key(&OutputType::Exe); let needs_crate_object = - sess.opts.output_types.contains(&config::OutputTypeExe); + sess.opts.output_types.contains_key(&OutputType::Exe); if needs_crate_bitcode { modules_config.emit_bc = true; } - for output_type in output_types { + for output_type in output_types.keys() { match *output_type { - config::OutputTypeBitcode => { modules_config.emit_bc = true; }, - config::OutputTypeLlvmAssembly => { modules_config.emit_ir = true; }, - config::OutputTypeAssembly => { + OutputType::Bitcode => { modules_config.emit_bc = true; }, + OutputType::LlvmAssembly => { modules_config.emit_ir = true; }, + OutputType::Assembly => { modules_config.emit_asm = true; // If we're not using the LLVM assembler, this function // could be invoked specially with output_type_assembly, so // in this case we still want the metadata object file. - if !sess.opts.output_types.contains(&config::OutputTypeAssembly) { + if !sess.opts.output_types.contains_key(&OutputType::Assembly) { metadata_config.emit_obj = true; } }, - config::OutputTypeObject => { modules_config.emit_obj = true; }, - config::OutputTypeExe => { + OutputType::Object => { modules_config.emit_obj = true; }, + OutputType::Exe => { modules_config.emit_obj = true; metadata_config.emit_obj = true; }, - config::OutputTypeDepInfo => {} + OutputType::DepInfo => {} } } @@ -686,8 +678,9 @@ pub fn run_passes(sess: &Session, } }; - let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| { - // Three cases: + let copy_if_one_unit = |ext: &str, + output_type: OutputType, + keep_numbered: bool| { if sess.opts.cg.codegen_units == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. @@ -697,17 +690,20 @@ pub fn run_passes(sess: &Session, // The user just wants `foo.x`, not `foo.0.x`. remove(sess, &crate_output.with_extension(ext)); } + } else if crate_output.outputs.contains_key(&output_type) { + // 2) Multiple codegen units, with `--emit foo=some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring emit path because multiple .{} files \ + were produced", ext)); + } else if crate_output.single_output_file.is_some() { + // 3) Multiple codegen units, with `-o some_name`. We have + // no good solution for this case, so warn the user. + sess.warn(&format!("ignoring -o because multiple .{} files \ + were produced", ext)); } else { - if crate_output.single_output_file.is_some() { - // 2) Multiple codegen units, with `-o some_name`. We have - // no good solution for this case, so warn the user. - sess.warn(&format!("ignoring -o because multiple .{} files were produced", - ext)); - } else { - // 3) Multiple codegen units, but no `-o some_name`. We - // just leave the `foo.0.x` files in place. - // (We don't have to do any work in this case.) - } + // 4) Multiple codegen units, but no explicit name. We + // just leave the `foo.0.x` files in place. + // (We don't have to do any work in this case.) } }; @@ -716,27 +712,27 @@ pub fn run_passes(sess: &Session, // to get rid of it. let mut user_wants_bitcode = false; let mut user_wants_objects = false; - for output_type in output_types { + for output_type in output_types.keys() { match *output_type { - config::OutputTypeBitcode => { + OutputType::Bitcode => { user_wants_bitcode = true; // Copy to .bc, but always keep the .0.bc. There is a later // check to figure out if we should delete .0.bc files, or keep // them for making an rlib. - copy_if_one_unit("0.bc", config::OutputTypeBitcode, true); + copy_if_one_unit("0.bc", OutputType::Bitcode, true); } - config::OutputTypeLlvmAssembly => { - copy_if_one_unit("0.ll", config::OutputTypeLlvmAssembly, false); + OutputType::LlvmAssembly => { + copy_if_one_unit("0.ll", OutputType::LlvmAssembly, false); } - config::OutputTypeAssembly => { - copy_if_one_unit("0.s", config::OutputTypeAssembly, false); + OutputType::Assembly => { + copy_if_one_unit("0.s", OutputType::Assembly, false); } - config::OutputTypeObject => { + OutputType::Object => { user_wants_objects = true; - copy_if_one_unit("0.o", config::OutputTypeObject, true); + copy_if_one_unit("0.o", OutputType::Object, true); } - config::OutputTypeExe | - config::OutputTypeDepInfo => {} + OutputType::Exe | + OutputType::DepInfo => {} } } let user_wants_bitcode = user_wants_bitcode; @@ -913,8 +909,8 @@ fn run_work_multithreaded(sess: &Session, pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { let (pname, mut cmd) = get_linker(sess); - cmd.arg("-c").arg("-o").arg(&outputs.path(config::OutputTypeObject)) - .arg(&outputs.temp_path(config::OutputTypeAssembly)); + cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object)) + .arg(&outputs.temp_path(OutputType::Assembly)); debug!("{:?}", cmd); match cmd.output() { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 2f47353fee7b2..15ec26e5afe10 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -23,7 +23,7 @@ use std::sync::{Arc, Mutex}; use testing; use rustc_lint; use rustc::session::{self, config}; -use rustc::session::config::get_unstable_features_setting; +use rustc::session::config::{get_unstable_features_setting, OutputType}; use rustc::session::search_paths::{SearchPaths, PathKind}; use rustc_front::lowering::lower_crate; use rustc_back::tempdir::TempDir; @@ -163,13 +163,15 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, // never wrap the test in `fn main() { ... }` let test = maketest(test, Some(cratename), as_test_harness, opts); let input = config::Input::Str(test.to_string()); + let mut outputs = HashMap::new(); + outputs.insert(OutputType::Exe, None); let sessopts = config::Options { maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap() .parent().unwrap().to_path_buf()), search_paths: libs, crate_types: vec!(config::CrateTypeExecutable), - output_types: vec!(config::OutputTypeExe), + output_types: outputs, externs: externs, cg: config::CodegenOptions { prefer_dynamic: true, diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 8745cbecf9137..bd8c735df31a9 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private, path, convert)] +#![feature(rustc_private)] extern crate rustc; extern crate rustc_driver; @@ -16,7 +16,7 @@ extern crate rustc_lint; extern crate syntax; use rustc::session::{build_session, Session}; -use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe}; +use rustc::session::config::{basic_options, build_configuration, Input, OutputType}; use rustc_driver::driver::{compile_input, CompileController}; use syntax::diagnostics::registry::Registry; @@ -46,7 +46,7 @@ fn main() { fn basic_sess(sysroot: PathBuf) -> Session { let mut opts = basic_options(); - opts.output_types = vec![OutputTypeExe]; + opts.output_types.insert(OutputType::Exe, None); opts.maybe_sysroot = Some(sysroot); let descriptions = Registry::new(&rustc::DIAGNOSTICS); diff --git a/src/test/run-make/output-type-permutations/Makefile b/src/test/run-make/output-type-permutations/Makefile index a785e916cf733..b4b2e827e947e 100644 --- a/src/test/run-make/output-type-permutations/Makefile +++ b/src/test/run-make/output-type-permutations/Makefile @@ -23,45 +23,83 @@ all: rm -f $(TMPDIR)/bar.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=asm -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=llvm-bc -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=llvm-ir -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=obj -o $(TMPDIR)/foo + $(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo + rm $(TMPDIR)/foo + $(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] - $(RUSTC) foo.rs --emit=link -o $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo) rm $(TMPDIR)/$(call BIN,foo) rm -f $(TMPDIR)/foo.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo + rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo) rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) rm -f $(TMPDIR)/foo.{exp,lib,pdb} [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo rm $(TMPDIR)/foo + $(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo + rm $(TMPDIR)/foo [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo) rm $(TMPDIR)/$(call BIN,foo) + $(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo) + rm $(TMPDIR)/$(call BIN,foo) rm -f $(TMPDIR)/foo.pdb [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] + $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \ + --emit link \ + --crate-type=rlib + rm $(TMPDIR)/ir + rm $(TMPDIR)/libbar.rlib + [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] + + $(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \ + --emit llvm-ir=$(TMPDIR)/ir \ + --emit llvm-bc=$(TMPDIR)/bc \ + --emit obj=$(TMPDIR)/obj \ + --emit link=$(TMPDIR)/link \ + --crate-type=staticlib + rm $(TMPDIR)/asm + rm $(TMPDIR)/ir + rm $(TMPDIR)/bc + rm $(TMPDIR)/obj + rm $(TMPDIR)/link + [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ] + $(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib rm $(TMPDIR)/bar.ll rm $(TMPDIR)/bar.s From 0294098d8f3e2926cf0e6adba9a96e47099c3c0f Mon Sep 17 00:00:00 2001 From: Simon Mazur Date: Wed, 30 Sep 2015 20:31:41 +0300 Subject: [PATCH 06/14] Implement `size_hint` for `EscapeUnicode` --- src/libcore/char.rs | 22 +++++++++++++++++++--- src/libcore/fmt/mod.rs | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 8d1af46691c70..ccce2ad22ddc2 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -342,6 +342,22 @@ impl Iterator for EscapeUnicode { EscapeUnicodeState::Done => None, } } + + fn size_hint(&self) -> (usize, Option) { + let mut n = 0; + while (self.c as usize) >> (4 * (n + 1)) != 0 { + n += 1; + } + let n = match self.state { + EscapeUnicodeState::Backslash => n + 5, + EscapeUnicodeState::Type => n + 4, + EscapeUnicodeState::LeftBrace => n + 3, + EscapeUnicodeState::Value(offset) => offset + 2, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Done => 0, + }; + (n, Some(n)) + } } /// An iterator over the characters that represent a `char`, escaped @@ -375,7 +391,7 @@ impl Iterator for EscapeDefault { Some(c) } EscapeDefaultState::Done => None, - EscapeDefaultState::Unicode(ref mut iter) => iter.next() + EscapeDefaultState::Unicode(ref mut iter) => iter.next(), } } @@ -383,8 +399,8 @@ impl Iterator for EscapeDefault { match self.state { EscapeDefaultState::Char(_) => (1, Some(1)), EscapeDefaultState::Backslash(_) => (2, Some(2)), - EscapeDefaultState::Unicode(_) => (0, Some(10)), - _ => (0, Some(0)) + EscapeDefaultState::Unicode(ref iter) => iter.size_hint(), + EscapeDefaultState::Done => (0, Some(0)), } } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 88b3963df8d9b..e226b5f2ca8fc 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1315,7 +1315,7 @@ impl Debug for str { for (i, c) in self.char_indices() { let esc = c.escape_default(); // If char needs escaping, flush backlog so far and write, else skip - if esc.size_hint().0 != 1 { + if esc.size_hint() != (1, Some(1)) { try!(f.write_str(&self[from..i])); for c in esc { try!(f.write_char(c)); From 8a4bfbb1c60a72a70b93f520bab0be6aabb3f132 Mon Sep 17 00:00:00 2001 From: William Throwe Date: Thu, 1 Oct 2015 23:25:48 -0400 Subject: [PATCH 07/14] Add a test that rustc can compile standard input --- src/test/run-make/compile-stdin/Makefile | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/test/run-make/compile-stdin/Makefile diff --git a/src/test/run-make/compile-stdin/Makefile b/src/test/run-make/compile-stdin/Makefile new file mode 100644 index 0000000000000..1442224cf9a76 --- /dev/null +++ b/src/test/run-make/compile-stdin/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: + echo 'fn main(){}' | $(RUSTC) - + $(call RUN,rust_out) From 98841d4e93b08f9a99a36edff48c44fcc3228b31 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 29 Sep 2015 23:37:36 +0300 Subject: [PATCH 08/14] Fix misnamed variable in rustdoc --- src/librustdoc/html/static/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 9a13d20854623..e32122ceb509e 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -133,7 +133,7 @@ $(document).on("keypress", handleShortcut); $(document).on("keydown", handleShortcut); $(document).on("click", function(ev) { - if (!$(e.target).closest("#help > div").length) { + if (!$(ev.target).closest("#help > div").length) { $("#help").addClass("hidden"); $("body").removeClass("blur"); } From f38bc2c45763f773c9373634dbbe58cc36bf8704 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Tue, 29 Sep 2015 23:47:01 +0300 Subject: [PATCH 09/14] Fix librustdoc search events Previously only keyup event was looked at, which meant that pasting, cutting and otherwise changing the input without typing would not catch any updates to the search query. --- src/librustdoc/html/static/main.js | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index e32122ceb509e..5a6d761683224 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -515,7 +515,6 @@ var $active = $results.filter('.highlighted'); if (e.which === 38) { // up - e.preventDefault(); if (!$active.length || !$active.prev()) { return; } @@ -523,7 +522,6 @@ $active.prev().addClass('highlighted'); $active.removeClass('highlighted'); } else if (e.which === 40) { // down - e.preventDefault(); if (!$active.length) { $results.first().addClass('highlighted'); } else if ($active.next().length) { @@ -531,7 +529,6 @@ $active.removeClass('highlighted'); } } else if (e.which === 13) { // return - e.preventDefault(); if ($active.length) { document.location.href = $active.find('a').prop('href'); } @@ -722,20 +719,29 @@ } function startSearch() { - - $(".search-input").on("keyup",function() { + var searchTimeout; + $(".search-input").on("keyup input",function() { + clearTimeout(searchTimeout); if ($(this).val().length === 0) { window.history.replaceState("", "std - Rust", "?search="); $('#main.content').removeClass('hidden'); $('#search.content').addClass('hidden'); + } else { + searchTimeout = setTimeout(search, 500); } }); - - var keyUpTimeout; - $('.do-search').on('click', search); - $('.search-input').on('keyup', function() { - clearTimeout(keyUpTimeout); - keyUpTimeout = setTimeout(search, 500); + $('.search-form').on('submit', function(e){ + e.preventDefault(); + clearTimeout(searchTimeout); + search(); + }); + $('.search-input').on('change paste', function(e) { + // Do NOT e.preventDefault() here. It will prevent pasting. + clearTimeout(searchTimeout); + // zero-timeout necessary here because at the time of event handler execution the + // pasted content is not in the input field yet. Shouldn’t make any difference for + // change, though. + setTimeout(search, 0); }); // Push and pop states are used to add search results to the browser From 20cccfa67f0266fb6aa914c3fd3bd37d68c19d07 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Fri, 25 Sep 2015 18:44:36 +0900 Subject: [PATCH 10/14] Change tests per RFC 246 (const vs static) --- src/test/auxiliary/sepcomp_cci_lib.rs | 3 +-- src/test/auxiliary/xcrate_static_addresses.rs | 3 --- src/test/run-pass/sepcomp-cci.rs | 12 ++++++------ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/test/auxiliary/sepcomp_cci_lib.rs b/src/test/auxiliary/sepcomp_cci_lib.rs index d62b98714026b..c57d161d8f574 100644 --- a/src/test/auxiliary/sepcomp_cci_lib.rs +++ b/src/test/auxiliary/sepcomp_cci_lib.rs @@ -13,5 +13,4 @@ pub fn cci_fn() -> usize { 1200 } -#[inline] -pub static CCI_STATIC: usize = 34; +pub const CCI_CONST: usize = 34; diff --git a/src/test/auxiliary/xcrate_static_addresses.rs b/src/test/auxiliary/xcrate_static_addresses.rs index 652f11a71ec6f..d0da80e31b913 100644 --- a/src/test/auxiliary/xcrate_static_addresses.rs +++ b/src/test/auxiliary/xcrate_static_addresses.rs @@ -8,13 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[inline(never)] pub static global: isize = 3; -#[inline(never)] static global0: isize = 4; -#[inline(never)] pub static global2: &'static isize = &global0; pub fn verify_same(a: &'static isize) { diff --git a/src/test/run-pass/sepcomp-cci.rs b/src/test/run-pass/sepcomp-cci.rs index a1c5ad113c76d..d3d3de0e2c0cb 100644 --- a/src/test/run-pass/sepcomp-cci.rs +++ b/src/test/run-pass/sepcomp-cci.rs @@ -16,23 +16,23 @@ extern crate sepcomp_cci_lib; -use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; +use sepcomp_cci_lib::{cci_fn, CCI_CONST}; fn call1() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } mod a { - use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; + use sepcomp_cci_lib::{cci_fn, CCI_CONST}; pub fn call2() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } } mod b { - use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; + use sepcomp_cci_lib::{cci_fn, CCI_CONST}; pub fn call3() -> usize { - cci_fn() + CCI_STATIC + cci_fn() + CCI_CONST } } From 61f5b2b0ca492a7eef9c362efb2108c77eac5bf8 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Fri, 25 Sep 2015 15:25:59 +0900 Subject: [PATCH 11/14] Check attribute usage --- src/librustc/front/check_attr.rs | 110 +++++++++++++++++++++ src/librustc/lib.rs | 1 + src/librustc_driver/driver.rs | 4 + src/librustc_front/attr.rs | 1 - src/libsyntax/attr.rs | 1 - src/test/compile-fail/attr-usage-inline.rs | 19 ++++ src/test/compile-fail/attr-usage-repr.rs | 41 ++++++++ 7 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 src/librustc/front/check_attr.rs create mode 100644 src/test/compile-fail/attr-usage-inline.rs create mode 100644 src/test/compile-fail/attr-usage-repr.rs diff --git a/src/librustc/front/check_attr.rs b/src/librustc/front/check_attr.rs new file mode 100644 index 0000000000000..cca14f1fbf2a3 --- /dev/null +++ b/src/librustc/front/check_attr.rs @@ -0,0 +1,110 @@ +// 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 session::Session; + +use syntax::ast; +use syntax::attr::AttrMetaMethods; +use syntax::visit; +use syntax::visit::Visitor; + +#[derive(Copy, Clone, PartialEq)] +enum Target { + Fn, + Struct, + Enum, + Other, +} + +impl Target { + fn from_item(item: &ast::Item) -> Target { + match item.node { + ast::ItemFn(..) => Target::Fn, + ast::ItemStruct(..) => Target::Struct, + ast::ItemEnum(..) => Target::Enum, + _ => Target::Other, + } + } +} + +struct CheckAttrVisitor<'a> { + sess: &'a Session, +} + +impl<'a> CheckAttrVisitor<'a> { + fn check_inline(&self, attr: &ast::Attribute, target: Target) { + if target != Target::Fn { + self.sess.span_err( + attr.span, + "attribute should be applied to function"); + } + } + + fn check_repr(&self, attr: &ast::Attribute, target: Target) { + let words = match attr.meta_item_list() { + Some(words) => words, + None => { + return; + } + }; + for word in words { + let word: &str = &word.name(); + match word { + "C" => { + if target != Target::Struct && target != Target::Enum { + self.sess.span_err( + attr.span, + "attribute should be applied to struct or enum"); + } + } + "packed" | + "simd" => { + if target != Target::Struct { + self.sess.span_err( + attr.span, + "attribute should be applied to struct"); + } + } + "i8" | "u8" | "i16" | "u16" | + "i32" | "u32" | "i64" | "u64" | + "isize" | "usize" => { + if target != Target::Enum { + self.sess.span_err( + attr.span, + "attribute should be applied to enum"); + } + } + _ => (), + } + } + } + + fn check_attribute(&self, attr: &ast::Attribute, target: Target) { + let name: &str = &attr.name(); + match name { + "inline" => self.check_inline(attr, target), + "repr" => self.check_repr(attr, target), + _ => (), + } + } +} + +impl<'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> { + fn visit_item(&mut self, item: &ast::Item) { + let target = Target::from_item(item); + for attr in &item.attrs { + self.check_attribute(attr, target); + } + } +} + +pub fn check_crate(sess: &Session, krate: &ast::Crate) { + visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate); +} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 0bbb57afc278e..e08dc2acbc088 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -101,6 +101,7 @@ pub mod back { } pub mod front { + pub mod check_attr; pub mod map; } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d004d557856b7..fdc522e330f18 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -129,6 +129,10 @@ pub fn compile_input(sess: Session, &ast_map.krate(), &id[..])); + time(sess.time_passes(), "attribute checking", || { + front::check_attr::check_crate(&sess, &expanded_crate); + }); + time(sess.time_passes(), "early lint checks", || { lint::check_ast_crate(&sess, &expanded_crate) }); diff --git a/src/librustc_front/attr.rs b/src/librustc_front/attr.rs index 9e1e3c0e293ac..1a564eb28a3a0 100644 --- a/src/librustc_front/attr.rs +++ b/src/librustc_front/attr.rs @@ -300,7 +300,6 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { - // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineAttr::None, |ia,attr| { match attr.node.value.node { MetaWord(ref n) if *n == "inline" => { diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5fe4220bd99ba..bd99d33222db1 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -323,7 +323,6 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr { - // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineAttr::None, |ia,attr| { match attr.node.value.node { MetaWord(ref n) if *n == "inline" => { diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs new file mode 100644 index 0000000000000..c6b9b016331aa --- /dev/null +++ b/src/test/compile-fail/attr-usage-inline.rs @@ -0,0 +1,19 @@ +// 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. + +#![allow(dead_code)] + +#[inline] +fn f() {} + +#[inline] //~ ERROR: attribute should be applied to function +struct S; + +fn main() {} diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs new file mode 100644 index 0000000000000..9bad6a8389a5d --- /dev/null +++ b/src/test/compile-fail/attr-usage-repr.rs @@ -0,0 +1,41 @@ +// 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. + +#![allow(dead_code)] +#![feature(repr_simd)] + +#[repr(C)] //~ ERROR: attribute should be applied to struct or enum +fn f() {} + +#[repr(C)] +struct SExtern(f64, f64); + +#[repr(packed)] +struct SPacked(f64, f64); + +#[repr(simd)] +struct SSimd(f64, f64); + +#[repr(i8)] //~ ERROR: attribute should be applied to enum +struct SInt(f64, f64); + +#[repr(C)] +enum EExtern { A, B } + +#[repr(packed)] //~ ERROR: attribute should be applied to struct +enum EPacked { A, B } + +#[repr(simd)] //~ ERROR: attribute should be applied to struct +enum ESimd { A, B } + +#[repr(i8)] +enum EInt { A, B } + +fn main() {} From 17419622712af44311aa7a8730e4535dff3554f5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 30 Sep 2015 10:17:07 -0700 Subject: [PATCH 12/14] rustc: Emit phony targets for inputs in dep-info This helps protect against files being deleted to ensure that `make` won't emit errors. Closes #28735 --- src/librustc_driver/driver.rs | 9 ++++++++- src/test/run-make/dep-info/Makefile | 10 ++++++++-- src/test/run-make/dep-info/lib2.rs | 13 +++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/test/run-make/dep-info/lib2.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index e2835ae8f0d6f..0ec3424b82d03 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -881,9 +881,16 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) { .collect(); let mut file = try!(fs::File::create(&deps_filename)); for path in &out_filenames { - try!(write!(&mut file, + try!(write!(file, "{}: {}\n\n", path.display(), files.join(" "))); } + + // Emit a fake target for each input file to the compilation. This + // prevents `make` from spitting out an error if a file is later + // deleted. For more info see #28735 + for path in files { + try!(writeln!(file, "{}:", path)); + } Ok(()) })(); diff --git a/src/test/run-make/dep-info/Makefile b/src/test/run-make/dep-info/Makefile index a1828cd1f5d73..9b79d1af52181 100644 --- a/src/test/run-make/dep-info/Makefile +++ b/src/test/run-make/dep-info/Makefile @@ -7,9 +7,10 @@ ifneq ($(shell uname),FreeBSD) ifndef IS_WINDOWS all: - $(RUSTC) --emit dep-info,link --crate-type=lib lib.rs + cp *.rs $(TMPDIR) + $(RUSTC) --emit dep-info,link --crate-type=lib $(TMPDIR)/lib.rs sleep 2 - touch foo.rs + touch $(TMPDIR)/foo.rs -rm -f $(TMPDIR)/done $(MAKE) -drf Makefile.foo sleep 2 @@ -17,6 +18,11 @@ all: pwd $(MAKE) -drf Makefile.foo rm $(TMPDIR)/done && exit 1 || exit 0 + + # When a source file is deleted `make` should still work + rm $(TMPDIR)/bar.rs + cp $(TMPDIR)/lib2.rs $(TMPDIR)/lib.rs + $(MAKE) -drf Makefile.foo else all: diff --git a/src/test/run-make/dep-info/lib2.rs b/src/test/run-make/dep-info/lib2.rs new file mode 100644 index 0000000000000..1b70fb4eb4b47 --- /dev/null +++ b/src/test/run-make/dep-info/lib2.rs @@ -0,0 +1,13 @@ +// Copyright 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. + +#![crate_name = "foo"] + +pub mod foo; From eac9d71d8ec4ea3b67e962e8af841dd601c93e88 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 2 Oct 2015 23:53:20 +0300 Subject: [PATCH 13/14] reference: fix markdown formatting --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index db3f4b064b1fb..2fce37eccae1c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -77,9 +77,12 @@ An identifier is any nonempty Unicode[^non_ascii_idents] string of the following gated. This is expected to improve soon. Either + * The first character has property `XID_start` * The remaining characters have property `XID_continue` + Or + * The first character is `_` * The identifier is more than one character, `_` alone is not an identifier * The remaining characters have property `XID_continue` From f528c47c4bb836dd7277dc7ce138a41d175e1dd3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 2 Oct 2015 18:54:07 -0400 Subject: [PATCH 14/14] Add in some
s for emphasis It's not really clear here, since the example is rendered, where it starts and ends. So let's use
s to split it up. --- src/doc/trpl/documentation.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 5afb9b7f868c8..1e1b2e2d4588b 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -279,6 +279,8 @@ println!("{}", x + y); Here's an explanation, rendered: +------------------------------------------------------------------------------- + First, we set `x` to five: ```rust @@ -303,8 +305,12 @@ Finally, we print the sum of `x` and `y`: println!("{}", x + y); ``` +------------------------------------------------------------------------------- + Here's the same explanation, in raw text: +------------------------------------------------------------------------------- + > First, we set `x` to five: > > ```text @@ -329,6 +335,8 @@ Here's the same explanation, in raw text: > println!("{}", x + y); > ``` +------------------------------------------------------------------------------- + By repeating all parts of the example, you can ensure that your example still compiles, while only showing the parts that are relevant to that part of your explanation.