diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 395b3879cfd0..64a506a6377f 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -316,7 +316,6 @@ impl *const T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] @@ -349,7 +348,6 @@ impl *const T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index b86ef5b13b35..6b5cd9fdb854 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -294,7 +294,6 @@ impl *mut T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] @@ -327,7 +326,6 @@ impl *mut T { /// differently have not been explored. This method should not be used to introduce such /// differences, and it should also not be stabilized before we have a better understanding /// of this issue. - /// ``` #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] #[inline] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index c69aafe687cf..d92d59ce2bfd 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1459,6 +1459,86 @@ impl [T] { m >= n && needle == &self[m - n..] } + /// Returns a subslice with the prefix removed. + /// + /// Returns [`None`] if slice does not start with `prefix`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = [10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// ``` + /// + /// This method returns the original slice if `prefix` is an empty slice: + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[]), Some(v)); + /// let v: &[u8] = &[]; + /// assert_eq!(v.strip_prefix(&[]), Some(v)); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_prefix(&self, prefix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// Returns [`None`] if slice does not end with `suffix`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = [10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + /// + /// This method returns the original slice if `suffix` is an empty slice: + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[]), Some(v)); + /// let v: &[u8] = &[]; + /// assert_eq!(v.strip_suffix(&[]), Some(v)); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_suffix(&self, suffix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + /// Binary searches this sorted slice for a given element. /// /// If the value is found then [`Result::Ok`] is returned, containing the @@ -2817,6 +2897,7 @@ pub trait SliceIndex: private_slice_index::Sealed { /// performing any bounds checking. /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. + /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; @@ -2825,6 +2906,7 @@ pub trait SliceIndex: private_slice_index::Sealed { /// performing any bounds checking. /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. + /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; diff --git a/src/librustc_builtin_macros/env.rs b/src/librustc_builtin_macros/env.rs index d769ebb1f552..6c3a1ce0958e 100644 --- a/src/librustc_builtin_macros/env.rs +++ b/src/librustc_builtin_macros/env.rs @@ -22,8 +22,10 @@ pub fn expand_option_env<'cx>( }; let sp = cx.with_def_site_ctxt(sp); - let e = match env::var(&var.as_str()) { - Err(..) => { + let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern); + cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value)); + let e = match value { + None => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); cx.expr_path(cx.path_all( sp, @@ -37,10 +39,10 @@ pub fn expand_option_env<'cx>( ))], )) } - Ok(s) => cx.expr_call_global( + Some(value) => cx.expr_call_global( sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), - vec![cx.expr_str(sp, Symbol::intern(&s))], + vec![cx.expr_str(sp, value)], ), }; MacEager::expr(e) @@ -78,12 +80,14 @@ pub fn expand_env<'cx>( } let sp = cx.with_def_site_ctxt(sp); - let e = match env::var(&*var.as_str()) { - Err(_) => { + let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern); + cx.parse_sess.env_depinfo.borrow_mut().insert((var, value)); + let e = match value { + None => { cx.span_err(sp, &msg.as_str()); return DummyResult::any(sp); } - Ok(s) => cx.expr_str(sp, Symbol::intern(&s)), + Some(value) => cx.expr_str(sp, value), }; MacEager::expr(e) } diff --git a/src/librustc_builtin_macros/lib.rs b/src/librustc_builtin_macros/lib.rs index a0f82d65618f..f56d8a372a73 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/src/librustc_builtin_macros/lib.rs @@ -5,6 +5,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] +#![feature(inner_deref)] #![feature(nll)] #![feature(or_patterns)] #![feature(proc_macro_internals)] diff --git a/src/librustc_error_codes/error_codes/E0701.md b/src/librustc_error_codes/error_codes/E0701.md index 87f416ada180..4965e6431059 100644 --- a/src/librustc_error_codes/error_codes/E0701.md +++ b/src/librustc_error_codes/error_codes/E0701.md @@ -1,7 +1,7 @@ This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed on something other than a struct or enum. -Examples of erroneous code: +Erroneous code example: ```compile_fail,E0701 #[non_exhaustive] diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index b22da86c0918..1362a1155bcd 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -31,6 +31,9 @@ use std::path::Path; use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; use termcolor::{Buffer, Color, WriteColor}; +/// Default column width, used in tests and when terminal dimensions cannot be determined. +const DEFAULT_COLUMN_WIDTH: usize = 140; + /// Describes the way the content of the `rendered` field of the json output is generated #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum HumanReadableErrorType { @@ -74,7 +77,8 @@ struct Margin { pub computed_left: usize, /// The end of the line to be displayed. pub computed_right: usize, - /// The current width of the terminal. 140 by default and in tests. + /// The current width of the terminal. Uses value of `DEFAULT_COLUMN_WIDTH` constant by default + /// and in tests. pub column_width: usize, /// The end column of a span label, including the span. Doesn't account for labels not in the /// same line as the span. @@ -1414,11 +1418,11 @@ impl EmitterWriter { let column_width = if let Some(width) = self.terminal_width { width.saturating_sub(code_offset) } else if self.ui_testing { - 140 + DEFAULT_COLUMN_WIDTH } else { termize::dimensions() .map(|(w, _)| w.saturating_sub(code_offset)) - .unwrap_or(usize::MAX) + .unwrap_or(DEFAULT_COLUMN_WIDTH) }; let margin = Margin::new( diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index e9a4119f4a33..ed5e715ce708 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -549,6 +549,22 @@ fn escape_dep_filename(filename: &FileName) -> String { filename.to_string().replace(" ", "\\ ") } +// Makefile comments only need escaping newlines and `\`. +// The result can be unescaped by anything that can unescape `escape_default` and friends. +fn escape_dep_env(symbol: Symbol) -> String { + let s = symbol.as_str(); + let mut escaped = String::with_capacity(s.len()); + for c in s.chars() { + match c { + '\n' => escaped.push_str(r"\n"), + '\r' => escaped.push_str(r"\r"), + '\\' => escaped.push_str(r"\\"), + _ => escaped.push(c), + } + } + escaped +} + fn write_out_deps( sess: &Session, boxed_resolver: &Steal>>, @@ -604,6 +620,25 @@ fn write_out_deps( for path in files { writeln!(file, "{}:", path)?; } + + // Emit special comments with information about accessed environment variables. + let env_depinfo = sess.parse_sess.env_depinfo.borrow(); + if !env_depinfo.is_empty() { + let mut envs: Vec<_> = env_depinfo + .iter() + .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) + .collect(); + envs.sort_unstable(); + writeln!(file)?; + for (k, v) in envs { + write!(file, "# env-dep:{}", k)?; + if let Some(v) = v { + write!(file, "={}", v)?; + } + writeln!(file)?; + } + } + Ok(()) })(); diff --git a/src/librustc_session/parse.rs b/src/librustc_session/parse.rs index ddbc95fb1b0b..93b27cabfb67 100644 --- a/src/librustc_session/parse.rs +++ b/src/librustc_session/parse.rs @@ -135,6 +135,8 @@ pub struct ParseSess { pub symbol_gallery: SymbolGallery, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. pub reached_eof: Lock, + /// Environment variables accessed during the build and their values when they exist. + pub env_depinfo: Lock)>>, } impl ParseSess { @@ -160,6 +162,7 @@ impl ParseSess { gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), reached_eof: Lock::new(false), + env_depinfo: Default::default(), } } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 6d98c4d01c04..b6d4834b7ec8 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -965,11 +965,61 @@ mod move_keyword {} #[doc(keyword = "mut")] // -/// A mutable binding, reference, or pointer. +/// A mutable variable, reference, or pointer. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// `mut` can be used in several situations. The first is mutable variables, +/// which can be used anywhere you can bind a value to a variable name. Some +/// examples: /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// ```rust +/// // A mutable variable in the parameter list of a function. +/// fn foo(mut x: u8, y: u8) -> u8 { +/// x += y; +/// x +/// } +/// +/// // Modifying a mutable variable. +/// # #[allow(unused_assignments)] +/// let mut a = 5; +/// a = 6; +/// +/// assert_eq!(foo(3, 4), 7); +/// assert_eq!(a, 6); +/// ``` +/// +/// The second is mutable references. They can be created from `mut` variables +/// and must be unique: no other variables can have a mutable reference, nor a +/// shared reference. +/// +/// ```rust +/// // Taking a mutable reference. +/// fn push_two(v: &mut Vec) { +/// v.push(2); +/// } +/// +/// // A mutable reference cannot be taken to a non-mutable variable. +/// let mut v = vec![0, 1]; +/// // Passing a mutable reference. +/// push_two(&mut v); +/// +/// assert_eq!(v, vec![0, 1, 2]); +/// ``` +/// +/// ```rust,compile_fail,E0502 +/// let mut v = vec![0, 1]; +/// let mut_ref_v = &mut v; +/// ##[allow(unused)] +/// let ref_v = &v; +/// mut_ref_v.push(2); +/// ``` +/// +/// Mutable raw pointers work much like mutable references, with the added +/// possibility of not pointing to a valid object. The syntax is `*mut Type`. +/// +/// More information on mutable references and pointers can be found in``` +/// [Reference]. +/// +/// [Reference]: ../reference/types/pointer.html#mutable-references-mut mod mut_keyword {} #[doc(keyword = "pub")] diff --git a/src/test/run-make/env-dep-info/Makefile b/src/test/run-make/env-dep-info/Makefile new file mode 100644 index 000000000000..2be0b4b324b0 --- /dev/null +++ b/src/test/run-make/env-dep-info/Makefile @@ -0,0 +1,8 @@ +-include ../../run-make-fulldeps/tools.mk + +all: + EXISTING_ENV=1 EXISTING_OPT_ENV=1 $(RUSTC) --emit dep-info main.rs + $(CGREP) "# env-dep:EXISTING_ENV=1" < $(TMPDIR)/main.d + $(CGREP) "# env-dep:EXISTING_OPT_ENV=1" < $(TMPDIR)/main.d + $(CGREP) "# env-dep:NONEXISTENT_OPT_ENV" < $(TMPDIR)/main.d + $(CGREP) "# env-dep:ESCAPE\nESCAPE\\" < $(TMPDIR)/main.d diff --git a/src/test/run-make/env-dep-info/main.rs b/src/test/run-make/env-dep-info/main.rs new file mode 100644 index 000000000000..a25246bac792 --- /dev/null +++ b/src/test/run-make/env-dep-info/main.rs @@ -0,0 +1,6 @@ +fn main() { + env!("EXISTING_ENV"); + option_env!("EXISTING_OPT_ENV"); + option_env!("NONEXISTENT_OPT_ENV"); + option_env!("ESCAPE\nESCAPE\\"); +}