Skip to content

Commit

Permalink
Auto merge of #74019 - Manishearth:rollup-2st3jsk, r=Manishearth
Browse files Browse the repository at this point in the history
Rollup of 12 pull requests

Successful merges:

 - #73140 (Fallback to xml.etree.ElementTree)
 - #73670 (Add `format_args_capture` feature)
 - #73693 (Use exhaustive match in const_prop.rs)
 - #73845 (Use &raw in A|Rc::as_ptr)
 - #73861 (Create E0768)
 - #73881 (Standardize bibliographic citations in rustc API docs)
 - #73925 (Improve comments from #72617, as suggested by RalfJung)
 - #73949 ([mir-opt] Fix mis-optimization and other issues with the SimplifyArmIdentity pass)
 - #73984 (Edit docs for rustc_data_structures::graph::scc)
 - #73985 (Fix "getting started" link)
 - #73997 (fix typo)
 - #73999 (Bump mingw-check CI image from Ubuntu 16.04 to 18.04.)

Failed merges:

 - #74000 (add `lazy_normalization_consts` feature gate)

r? @ghost
  • Loading branch information
bors committed Jul 4, 2020
2 parents 9a13ef2 + d69a846 commit dbf3ae7
Show file tree
Hide file tree
Showing 45 changed files with 1,859 additions and 123 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ Thank you for your interest in contributing to Rust!

To get started, read the [Getting Started] guide in the [rustc-dev-guide].

[Getting Started]: https://rustc-dev-guide.rust-lang.org/getting-started.md
[Getting Started]: https://rustc-dev-guide.rust-lang.org/getting-started.html
[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The Rust build system uses a Python script called `x.py` to build the compiler,
which manages the bootstrapping process. More information about it can be found
by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].

[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.md
[gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html

### Building on a Unix-like system
Expand Down
2 changes: 1 addition & 1 deletion src/ci/docker/host-x86_64/mingw-check/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:16.04
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
Expand Down
47 changes: 47 additions & 0 deletions src/doc/unstable-book/src/library-features/format-args-capture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# `format_args_capture`

The tracking issue for this feature is: [#67984]

[#67984]: https://github.com/rust-lang/rust/issues/67984

------------------------

Enables `format_args!` (and macros which use `format_args!` in their implementation, such
as `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.
This avoids the need to pass named parameters when the binding in question
already exists in scope.

```rust
#![feature(format_args_capture)]

let (person, species, name) = ("Charlie Brown", "dog", "Snoopy");

// captures named argument `person`
print!("Hello {person}");

// captures named arguments `species` and `name`
format!("The {species}'s name is {name}.");
```

This also works for formatting parameters such as width and precision:

```rust
#![feature(format_args_capture)]

let precision = 2;
let s = format!("{:.precision$}", 1.324223);

assert_eq!(&s, "1.32");
```

A non-exhaustive list of macros which benefit from this functionality include:
- `format!`
- `print!` and `println!`
- `eprint!` and `eprintln!`
- `write!` and `writeln!`
- `panic!`
- `unreachable!`
- `unimplemented!`
- `todo!`
- `assert!` and similar
- macros in many thirdparty crates, such as `log`
5 changes: 4 additions & 1 deletion src/etc/htmldocck.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@
from html.parser import HTMLParser
except ImportError:
from HTMLParser import HTMLParser
from xml.etree import cElementTree as ET
try:
from xml.etree import cElementTree as ET
except ImportError:
from xml.etree import ElementTree as ET

try:
from html.entities import name2codepoint
Expand Down
2 changes: 2 additions & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
#![feature(fundamental)]
#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(negative_impls)]
#![feature(new_uninit)]
Expand All @@ -109,6 +110,7 @@
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(ptr_offset_from)]
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(receiver_trait)]
#![feature(min_specialization)]
Expand Down
51 changes: 29 additions & 22 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
use core::iter;
use core::marker::{self, PhantomData, Unpin, Unsize};
use core::mem::{self, align_of, align_of_val, forget, size_of_val};
use core::mem::{self, align_of_val_raw, forget, size_of_val};
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
use core::pin::Pin;
use core::ptr::{self, NonNull};
Expand Down Expand Up @@ -591,17 +591,11 @@ impl<T: ?Sized> Rc<T> {
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub fn as_ptr(this: &Self) -> *const T {
let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
let fake_ptr = ptr as *mut T;

// SAFETY: This cannot go through Deref::deref.
// Instead, we manually offset the pointer rather than manifesting a reference.
// This is so that the returned pointer retains the same provenance as our pointer.
// This is required so that e.g. `get_mut` can write through the pointer
// after the Rc is recovered through `from_raw`.
unsafe {
let offset = data_offset(&(*ptr).value);
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
}
// SAFETY: This cannot go through Deref::deref or Rc::inner because
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
// write through the pointer after the Rc is recovered through `from_raw`.
unsafe { &raw const (*ptr).value }
}

/// Constructs an `Rc<T>` from a raw pointer.
Expand Down Expand Up @@ -1647,6 +1641,7 @@ pub struct Weak<T: ?Sized> {
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
// to allocate space on the heap. That's not a value a real pointer
// will ever have because RcBox has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<RcBox<T>>,
}

Expand Down Expand Up @@ -1708,9 +1703,18 @@ impl<T> Weak<T> {
/// [`null`]: ../../std/ptr/fn.null.html
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub fn as_ptr(&self) -> *const T {
let offset = data_offset_sized::<T>();
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
ptr as *const T
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);

// SAFETY: we must offset the pointer manually, and said pointer may be
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
// because we know that a pointer to unsized T was derived from a real
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
// is used so that we can use the same code path for the non-dangling
// unsized case and the potentially dangling sized case.
unsafe {
let offset = data_offset(ptr as *mut T);
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
}
}

/// Consumes the `Weak<T>` and turns it into a raw pointer.
Expand Down Expand Up @@ -2113,19 +2117,22 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
#[stable(feature = "pin", since = "1.33.0")]
impl<T: ?Sized> Unpin for Rc<T> {}

/// Get the offset within an `ArcInner` for
/// a payload of type described by a pointer.
///
/// # Safety
///
/// This has the same safety requirements as `align_of_val_raw`. In effect:
///
/// - This function is safe for any argument if `T` is sized, and
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
/// aquired from the real instance that you are getting this offset for.
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
// Align the unsized value to the end of the `RcBox`.
// Because it is ?Sized, it will always be the last field in memory.
// Note: This is a detail of the current implementation of the compiler,
// and is not a guaranteed language detail. Do not rely on it outside of std.
unsafe { data_offset_align(align_of_val(&*ptr)) }
}

/// Computes the offset of the data field within `RcBox`.
///
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
fn data_offset_sized<T>() -> isize {
data_offset_align(align_of::<T>())
unsafe { data_offset_align(align_of_val_raw(ptr)) }
}

#[inline]
Expand Down
50 changes: 28 additions & 22 deletions src/liballoc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use core::hash::{Hash, Hasher};
use core::intrinsics::abort;
use core::iter;
use core::marker::{PhantomData, Unpin, Unsize};
use core::mem::{self, align_of, align_of_val, size_of_val};
use core::mem::{self, align_of_val, size_of_val};
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
use core::pin::Pin;
use core::ptr::{self, NonNull};
Expand Down Expand Up @@ -267,6 +267,7 @@ pub struct Weak<T: ?Sized> {
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
// to allocate space on the heap. That's not a value a real pointer
// will ever have because RcBox has alignment at least 2.
// This is only possible when `T: Sized`; unsized `T` never dangle.
ptr: NonNull<ArcInner<T>>,
}

Expand Down Expand Up @@ -590,17 +591,11 @@ impl<T: ?Sized> Arc<T> {
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub fn as_ptr(this: &Self) -> *const T {
let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
let fake_ptr = ptr as *mut T;

// SAFETY: This cannot go through Deref::deref.
// Instead, we manually offset the pointer rather than manifesting a reference.
// This is so that the returned pointer retains the same provenance as our pointer.
// This is required so that e.g. `get_mut` can write through the pointer
// after the Arc is recovered through `from_raw`.
unsafe {
let offset = data_offset(&(*ptr).data);
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
}
// SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
// write through the pointer after the Rc is recovered through `from_raw`.
unsafe { &raw const (*ptr).data }
}

/// Constructs an `Arc<T>` from a raw pointer.
Expand Down Expand Up @@ -1476,9 +1471,18 @@ impl<T> Weak<T> {
/// [`null`]: ../../std/ptr/fn.null.html
#[stable(feature = "weak_into_raw", since = "1.45.0")]
pub fn as_ptr(&self) -> *const T {
let offset = data_offset_sized::<T>();
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
ptr as *const T
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);

// SAFETY: we must offset the pointer manually, and said pointer may be
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
// because we know that a pointer to unsized T was derived from a real
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
// is used so that we can use the same code path for the non-dangling
// unsized case and the potentially dangling sized case.
unsafe {
let offset = data_offset(ptr as *mut T);
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
}
}

/// Consumes the `Weak<T>` and turns it into a raw pointer.
Expand Down Expand Up @@ -2270,7 +2274,16 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
#[stable(feature = "pin", since = "1.33.0")]
impl<T: ?Sized> Unpin for Arc<T> {}

/// Computes the offset of the data field within `ArcInner`.
/// Get the offset within an `ArcInner` for
/// a payload of type described by a pointer.
///
/// # Safety
///
/// This has the same safety requirements as `align_of_val_raw`. In effect:
///
/// - This function is safe for any argument if `T` is sized, and
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
/// aquired from the real instance that you are getting this offset for.
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
// Align the unsized value to the end of the `ArcInner`.
// Because it is `?Sized`, it will always be the last field in memory.
Expand All @@ -2279,13 +2292,6 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
unsafe { data_offset_align(align_of_val(&*ptr)) }
}

/// Computes the offset of the data field within `ArcInner`.
///
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
fn data_offset_sized<T>() -> isize {
data_offset_align(align_of::<T>())
}

#[inline]
fn data_offset_align(align: usize) -> isize {
let layout = Layout::new::<ArcInner<()>>();
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ mod impls {
)]
#[lang = "discriminant_kind"]
pub trait DiscriminantKind {
/// The type of the dicriminant, which must satisfy the trait
/// The type of the discriminant, which must satisfy the trait
/// bounds required by `mem::Discriminant`.
type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin;
}
Expand Down
10 changes: 4 additions & 6 deletions src/librustc_ast_pretty/pp.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
//! This pretty-printer is a direct reimplementation of Philip Karlton's
//! Mesa pretty-printer, as described in appendix A of
//!
//! ```text
//! STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen.
//! Stanford Department of Computer Science, 1979.
//! ```
//! Mesa pretty-printer, as described in the appendix to
//! Derek C. Oppen, "Pretty Printing" (1979),
//! Stanford Computer Science Department STAN-CS-79-770,
//! <http://i.stanford.edu/pub/cstr/reports/cs/tr/79/770/CS-TR-79-770.pdf>.
//!
//! The algorithm's aim is to break a stream into as few lines as possible
//! while respecting the indentation-consistency requirements of the enclosing
Expand Down
57 changes: 53 additions & 4 deletions src/librustc_builtin_macros/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ struct Context<'a, 'b> {
arg_spans: Vec<Span>,
/// All the formatting arguments that have formatting flags set, in order for diagnostics.
arg_with_formatting: Vec<parse::FormatSpec<'a>>,

/// Whether this format string came from a string literal, as opposed to a macro.
is_literal: bool,
}

/// Parses the arguments from the given list of tokens, returning the diagnostic
Expand Down Expand Up @@ -498,10 +501,55 @@ impl<'a, 'b> Context<'a, 'b> {
self.verify_arg_type(Exact(idx), ty)
}
None => {
let msg = format!("there is no argument named `{}`", name);
let sp = *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp);
let mut err = self.ecx.struct_span_err(sp, &msg[..]);
err.emit();
let capture_feature_enabled = self
.ecx
.ecfg
.features
.map_or(false, |features| features.format_args_capture);

// For the moment capturing variables from format strings expanded from macros is
// disabled (see RFC #2795)
let can_capture = capture_feature_enabled && self.is_literal;

if can_capture {
// Treat this name as a variable to capture from the surrounding scope
let idx = self.args.len();
self.arg_types.push(Vec::new());
self.arg_unique_types.push(Vec::new());
self.args.push(
self.ecx.expr_ident(self.fmtsp, Ident::new(name, self.fmtsp)),
);
self.names.insert(name, idx);
self.verify_arg_type(Exact(idx), ty)
} else {
let msg = format!("there is no argument named `{}`", name);
let sp = if self.is_literal {
*self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
} else {
self.fmtsp
};
let mut err = self.ecx.struct_span_err(sp, &msg[..]);

if capture_feature_enabled && !self.is_literal {
err.note(&format!(
"did you intend to capture a variable `{}` from \
the surrounding scope?",
name
));
err.note(
"to avoid ambiguity, `format_args!` cannot capture variables \
when the format string is expanded from a macro",
);
} else if self.ecx.parse_sess().unstable_features.is_nightly_build() {
err.help(&format!(
"if you intended to capture `{}` from the surrounding scope, add \
`#![feature(format_args_capture)]` to the crate attributes",
name
));
}

err.emit();
}
}
}
}
Expand Down Expand Up @@ -951,6 +999,7 @@ pub fn expand_preparsed_format_args(
invalid_refs: Vec::new(),
arg_spans,
arg_with_formatting: Vec::new(),
is_literal: parser.is_literal,
};

// This needs to happen *after* the Parser has consumed all pieces to create all the spans
Expand Down
11 changes: 6 additions & 5 deletions src/librustc_data_structures/graph/dominators/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Algorithm citation:
//! A Simple, Fast Dominance Algorithm.
//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
//! Rice Computer Science TS-06-33870
//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>
//! Finding the dominators in a control-flow graph.
//!
//! Algorithm based on Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy,
//! "A Simple, Fast Dominance Algorithm",
//! Rice Computer Science TS-06-33870,
//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>.

use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
Expand Down
Loading

0 comments on commit dbf3ae7

Please sign in to comment.