mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #60030 - Centril:rollup-3d0t24t, r=Centril
Rollup of 5 pull requests Successful merges: - #59128 (Emit ansi color codes in the `rendered` field of json diagnostics) - #59646 (const fn: Improve wording) - #59986 (Miri: refactor new allocation tagging) - #60003 (LLD is not supported on Darwin) - #60018 (Miri now supports entropy, but is still slow) Failed merges: r? @ghost
This commit is contained in:
commit
efe2f32a6b
@ -156,8 +156,10 @@ impl Step for Llvm {
|
||||
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
|
||||
|
||||
if builder.config.llvm_thin_lto && !emscripten {
|
||||
cfg.define("LLVM_ENABLE_LTO", "Thin")
|
||||
.define("LLVM_ENABLE_LLD", "ON");
|
||||
cfg.define("LLVM_ENABLE_LTO", "Thin");
|
||||
if !target.contains("apple") {
|
||||
cfg.define("LLVM_ENABLE_LLD", "ON");
|
||||
}
|
||||
}
|
||||
|
||||
// By default, LLVM will automatically find OCaml and, if it finds it,
|
||||
|
@ -282,7 +282,7 @@ fn assert_covariance() {
|
||||
//
|
||||
// Destructors must be called exactly once per element.
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri does not support panics nor entropy
|
||||
#[cfg(not(miri))] // Miri does not support catching panics
|
||||
fn panic_safe() {
|
||||
static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
|
@ -389,7 +389,7 @@ fn test_reverse() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri does not support entropy
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
fn test_sort() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@ -466,10 +466,19 @@ fn test_sort() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri does not support entropy
|
||||
fn test_sort_stability() {
|
||||
for len in (2..25).chain(500..510) {
|
||||
for _ in 0..10 {
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
let large_range = 500..510;
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
let rounds = 10;
|
||||
|
||||
#[cfg(miri)]
|
||||
let large_range = 0..0; // empty range
|
||||
#[cfg(miri)]
|
||||
let rounds = 1;
|
||||
|
||||
for len in (2..25).chain(large_range) {
|
||||
for _ in 0..rounds {
|
||||
let mut counts = [0; 10];
|
||||
|
||||
// create a vector like [(6, 1), (5, 1), (6, 2), ...],
|
||||
@ -1397,7 +1406,7 @@ fn test_box_slice_clone() {
|
||||
#[test]
|
||||
#[allow(unused_must_use)] // here, we care about the side effects of `.clone()`
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg(not(miri))] // Miri does not support threads nor entropy
|
||||
#[cfg(not(miri))] // Miri does not support threads
|
||||
fn test_box_slice_clone_panics() {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@ -1589,7 +1598,7 @@ thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)] // no threads
|
||||
#[cfg(not(miri))] // Miri does not support threads nor entropy
|
||||
#[cfg(not(miri))] // Miri does not support threads
|
||||
fn panic_safe() {
|
||||
let prev = panic::take_hook();
|
||||
panic::set_hook(Box::new(move |info| {
|
||||
|
@ -1024,22 +1024,31 @@ fn test_rotate_right() {
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(miri))] // Miri does not support entropy
|
||||
fn sort_unstable() {
|
||||
use core::cmp::Ordering::{Equal, Greater, Less};
|
||||
use core::slice::heapsort;
|
||||
use rand::{FromEntropy, Rng, rngs::SmallRng, seq::SliceRandom};
|
||||
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
let large_range = 500..510;
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
let rounds = 100;
|
||||
|
||||
#[cfg(miri)]
|
||||
let large_range = 0..0; // empty range
|
||||
#[cfg(miri)]
|
||||
let rounds = 1;
|
||||
|
||||
let mut v = [0; 600];
|
||||
let mut tmp = [0; 600];
|
||||
let mut rng = SmallRng::from_entropy();
|
||||
|
||||
for len in (2..25).chain(500..510) {
|
||||
for len in (2..25).chain(large_range) {
|
||||
let v = &mut v[0..len];
|
||||
let tmp = &mut tmp[0..len];
|
||||
|
||||
for &modulus in &[5, 10, 100, 1000] {
|
||||
for _ in 0..100 {
|
||||
for _ in 0..rounds {
|
||||
for i in 0..len {
|
||||
v[i] = rng.gen::<i32>() % modulus;
|
||||
}
|
||||
@ -1095,7 +1104,7 @@ fn sort_unstable() {
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg(not(miri))] // Miri does not support entropy
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
fn partition_at_index() {
|
||||
use core::cmp::Ordering::{Equal, Greater, Less};
|
||||
use rand::rngs::SmallRng;
|
||||
|
@ -45,12 +45,10 @@ pub struct Allocation<Tag=(),Extra=()> {
|
||||
}
|
||||
|
||||
|
||||
pub trait AllocationExtra<Tag, MemoryExtra>: ::std::fmt::Debug + Clone {
|
||||
/// Hook to initialize the extra data when an allocation gets created.
|
||||
fn memory_allocated(
|
||||
_size: Size,
|
||||
_memory_extra: &MemoryExtra
|
||||
) -> Self;
|
||||
pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone {
|
||||
// There is no constructor in here because the constructor's type depends
|
||||
// on `MemoryKind`, and making things sufficiently generic leads to painful
|
||||
// inference failure.
|
||||
|
||||
/// Hook for performing extra checks on a memory read access.
|
||||
///
|
||||
@ -88,15 +86,8 @@ pub trait AllocationExtra<Tag, MemoryExtra>: ::std::fmt::Debug + Clone {
|
||||
}
|
||||
}
|
||||
|
||||
impl AllocationExtra<(), ()> for () {
|
||||
#[inline(always)]
|
||||
fn memory_allocated(
|
||||
_size: Size,
|
||||
_memory_extra: &()
|
||||
) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
// For Tag=() and no extra state, we have is a trivial implementation.
|
||||
impl AllocationExtra<()> for () { }
|
||||
|
||||
impl<Tag, Extra> Allocation<Tag, Extra> {
|
||||
/// Creates a read-only allocation initialized by the given bytes
|
||||
@ -159,7 +150,7 @@ impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
/// Byte accessors
|
||||
impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
|
||||
/// The last argument controls whether we error out when there are undefined
|
||||
/// or pointer bytes. You should never call this, call `get_bytes` or
|
||||
/// `get_bytes_with_undef_and_ptr` instead,
|
||||
@ -167,15 +158,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// This function also guarantees that the resulting pointer will remain stable
|
||||
/// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
|
||||
/// on that.
|
||||
fn get_bytes_internal<MemoryExtra>(
|
||||
fn get_bytes_internal(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size,
|
||||
check_defined_and_ptr: bool,
|
||||
) -> EvalResult<'tcx, &[u8]>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
self.check_bounds(cx, ptr, size)?;
|
||||
|
||||
@ -196,14 +185,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_bytes<MemoryExtra>(
|
||||
pub fn get_bytes(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size,
|
||||
) -> EvalResult<'tcx, &[u8]>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
self.get_bytes_internal(cx, ptr, size, true)
|
||||
}
|
||||
@ -211,28 +198,24 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// It is the caller's responsibility to handle undefined and pointer bytes.
|
||||
/// However, this still checks that there are no relocations on the *edges*.
|
||||
#[inline]
|
||||
pub fn get_bytes_with_undef_and_ptr<MemoryExtra>(
|
||||
pub fn get_bytes_with_undef_and_ptr(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size,
|
||||
) -> EvalResult<'tcx, &[u8]>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
self.get_bytes_internal(cx, ptr, size, false)
|
||||
}
|
||||
|
||||
/// Just calling this already marks everything as defined and removes relocations,
|
||||
/// so be sure to actually put data there!
|
||||
pub fn get_bytes_mut<MemoryExtra>(
|
||||
pub fn get_bytes_mut(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size,
|
||||
) -> EvalResult<'tcx, &mut [u8]>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
|
||||
self.check_bounds(cx, ptr, size)?;
|
||||
@ -250,16 +233,14 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
/// Reading and writing
|
||||
impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
|
||||
/// Reads bytes until a `0` is encountered. Will error if the end of the allocation is reached
|
||||
/// before a `0` is found.
|
||||
pub fn read_c_str<MemoryExtra>(
|
||||
pub fn read_c_str(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
) -> EvalResult<'tcx, &[u8]>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
|
||||
let offset = ptr.offset.bytes() as usize;
|
||||
@ -278,15 +259,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
|
||||
/// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
|
||||
/// given range contains neither relocations nor undef bytes.
|
||||
pub fn check_bytes<MemoryExtra>(
|
||||
pub fn check_bytes(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size,
|
||||
allow_ptr_and_undef: bool,
|
||||
) -> EvalResult<'tcx>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
// Check bounds and relocations on the edges
|
||||
self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
|
||||
@ -301,14 +280,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// Writes `src` to the memory starting at `ptr.offset`.
|
||||
///
|
||||
/// Will do bounds checks on the allocation.
|
||||
pub fn write_bytes<MemoryExtra>(
|
||||
pub fn write_bytes(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
src: &[u8],
|
||||
) -> EvalResult<'tcx>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(src.len() as u64))?;
|
||||
bytes.clone_from_slice(src);
|
||||
@ -316,15 +293,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
|
||||
pub fn write_repeat<MemoryExtra>(
|
||||
pub fn write_repeat(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
val: u8,
|
||||
count: Size
|
||||
) -> EvalResult<'tcx>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
let bytes = self.get_bytes_mut(cx, ptr, count)?;
|
||||
for b in bytes {
|
||||
@ -341,14 +316,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// being valid for ZSTs
|
||||
///
|
||||
/// Note: This function does not do *any* alignment checks, you need to do these before calling
|
||||
pub fn read_scalar<MemoryExtra>(
|
||||
pub fn read_scalar(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
size: Size
|
||||
) -> EvalResult<'tcx, ScalarMaybeUndef<Tag>>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
// get_bytes_unchecked tests relocation edges
|
||||
let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
|
||||
@ -379,13 +352,11 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
/// Note: This function does not do *any* alignment checks, you need to do these before calling
|
||||
pub fn read_ptr_sized<MemoryExtra>(
|
||||
pub fn read_ptr_sized(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
) -> EvalResult<'tcx, ScalarMaybeUndef<Tag>>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
self.read_scalar(cx, ptr, cx.data_layout().pointer_size)
|
||||
}
|
||||
@ -398,15 +369,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
/// being valid for ZSTs
|
||||
///
|
||||
/// Note: This function does not do *any* alignment checks, you need to do these before calling
|
||||
pub fn write_scalar<MemoryExtra>(
|
||||
pub fn write_scalar(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
val: ScalarMaybeUndef<Tag>,
|
||||
type_size: Size,
|
||||
) -> EvalResult<'tcx>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
let val = match val {
|
||||
ScalarMaybeUndef::Scalar(scalar) => scalar,
|
||||
@ -446,14 +415,12 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||
}
|
||||
|
||||
/// Note: This function does not do *any* alignment checks, you need to do these before calling
|
||||
pub fn write_ptr_sized<MemoryExtra>(
|
||||
pub fn write_ptr_sized(
|
||||
&mut self,
|
||||
cx: &impl HasDataLayout,
|
||||
ptr: Pointer<Tag>,
|
||||
val: ScalarMaybeUndef<Tag>
|
||||
) -> EvalResult<'tcx>
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
|
||||
where Extra: AllocationExtra<Tag, MemoryExtra>
|
||||
{
|
||||
let ptr_size = cx.data_layout().pointer_size;
|
||||
self.write_scalar(cx, ptr.into(), val, ptr_size)
|
||||
|
@ -94,11 +94,17 @@ impl<'tcx> Pointer<()> {
|
||||
Pointer { alloc_id, offset, tag: () }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_tag<Tag>(self, tag: Tag) -> Pointer<Tag>
|
||||
{
|
||||
Pointer::new_with_tag(self.alloc_id, self.offset, tag)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
|
||||
self.with_tag(Tag::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,13 +119,18 @@ impl<Tag> fmt::Display for Scalar<Tag> {
|
||||
|
||||
impl<'tcx> Scalar<()> {
|
||||
#[inline]
|
||||
pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> {
|
||||
match self {
|
||||
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)),
|
||||
Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
match self {
|
||||
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
|
||||
Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
|
||||
}
|
||||
self.with_tag(Tag::default())
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,14 +143,6 @@ impl<'tcx, Tag> Scalar<Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_tag(self, new_tag: Tag) -> Self {
|
||||
match self {
|
||||
Scalar::Ptr(ptr) => Scalar::Ptr(Pointer { tag: new_tag, ..ptr }),
|
||||
Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ptr_null(cx: &impl HasDataLayout) -> Self {
|
||||
Scalar::Bits {
|
||||
@ -434,13 +431,18 @@ impl<Tag> fmt::Display for ScalarMaybeUndef<Tag> {
|
||||
|
||||
impl<'tcx> ScalarMaybeUndef<()> {
|
||||
#[inline]
|
||||
pub fn with_tag<Tag>(self, new_tag: Tag) -> ScalarMaybeUndef<Tag> {
|
||||
match self {
|
||||
ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_tag(new_tag)),
|
||||
ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
match self {
|
||||
ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
|
||||
ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
|
||||
}
|
||||
self.with_tag(Tag::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use syntax::parse::token;
|
||||
use syntax::parse;
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::feature_gate::UnstableFeatures;
|
||||
use errors::emitter::HumanReadableErrorType;
|
||||
|
||||
use errors::{ColorConfig, FatalError, Handler};
|
||||
|
||||
@ -219,14 +220,18 @@ impl OutputType {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ErrorOutputType {
|
||||
HumanReadable(ColorConfig),
|
||||
Json(bool),
|
||||
Short(ColorConfig),
|
||||
HumanReadable(HumanReadableErrorType),
|
||||
Json {
|
||||
/// Render the json in a human readable way (with indents and newlines)
|
||||
pretty: bool,
|
||||
/// The way the `rendered` field is created
|
||||
json_rendered: HumanReadableErrorType,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for ErrorOutputType {
|
||||
fn default() -> ErrorOutputType {
|
||||
ErrorOutputType::HumanReadable(ColorConfig::Auto)
|
||||
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1372,6 +1377,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"print some statistics about AST and HIR"),
|
||||
always_encode_mir: bool = (false, parse_bool, [TRACKED],
|
||||
"encode MIR of all functions into the crate metadata"),
|
||||
json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||
"describes how to render the `rendered` field of json diagnostics"),
|
||||
unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
|
||||
"take the breaks off const evaluation. NOTE: this is unsound"),
|
||||
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
|
||||
@ -1825,6 +1832,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
|
||||
"How errors and other messages are produced",
|
||||
"human|json|short",
|
||||
),
|
||||
opt::opt(
|
||||
"",
|
||||
"json-rendered",
|
||||
"Choose `rendered` field of json diagnostics render scheme",
|
||||
"plain|termcolor",
|
||||
),
|
||||
opt::opt_s(
|
||||
"",
|
||||
"color",
|
||||
@ -1965,6 +1978,17 @@ pub fn build_session_options_and_crate_config(
|
||||
)
|
||||
}
|
||||
|
||||
let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() {
|
||||
"plain" => None,
|
||||
"termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)),
|
||||
_ => early_error(
|
||||
ErrorOutputType::default(),
|
||||
&format!(
|
||||
"argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)",
|
||||
s,
|
||||
),
|
||||
),
|
||||
}).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never));
|
||||
|
||||
// We need the opts_present check because the driver will send us Matches
|
||||
// with only stable options if no unstable options are used. Since error-format
|
||||
@ -1972,14 +1996,14 @@ pub fn build_session_options_and_crate_config(
|
||||
// opt_present because the latter will panic.
|
||||
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
|
||||
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
|
||||
Some("human") => ErrorOutputType::HumanReadable(color),
|
||||
Some("json") => ErrorOutputType::Json(false),
|
||||
Some("pretty-json") => ErrorOutputType::Json(true),
|
||||
Some("short") => ErrorOutputType::Short(color),
|
||||
None => ErrorOutputType::HumanReadable(color),
|
||||
None |
|
||||
Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
|
||||
Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
|
||||
Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
|
||||
Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
|
||||
|
||||
Some(arg) => early_error(
|
||||
ErrorOutputType::HumanReadable(color),
|
||||
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
|
||||
&format!(
|
||||
"argument for --error-format must be `human`, `json` or \
|
||||
`short` (instead was `{}`)",
|
||||
@ -1988,7 +2012,7 @@ pub fn build_session_options_and_crate_config(
|
||||
),
|
||||
}
|
||||
} else {
|
||||
ErrorOutputType::HumanReadable(color)
|
||||
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
|
||||
};
|
||||
|
||||
let unparsed_crate_types = matches.opt_strs("crate-type");
|
||||
@ -2000,11 +2024,16 @@ pub fn build_session_options_and_crate_config(
|
||||
|
||||
let mut debugging_opts = build_debugging_options(matches, error_format);
|
||||
|
||||
if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
|
||||
early_error(
|
||||
ErrorOutputType::Json(false),
|
||||
"--error-format=pretty-json is unstable",
|
||||
);
|
||||
if !debugging_opts.unstable_options {
|
||||
if matches.opt_str("json-rendered").is_some() {
|
||||
early_error(error_format, "`--json-rendered=x` is unstable");
|
||||
}
|
||||
if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
|
||||
early_error(
|
||||
ErrorOutputType::Json { pretty: false, json_rendered },
|
||||
"--error-format=pretty-json is unstable",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() {
|
||||
@ -2928,50 +2957,55 @@ mod tests {
|
||||
let mut v3 = Options::default();
|
||||
let mut v4 = Options::default();
|
||||
|
||||
const JSON: super::ErrorOutputType = super::ErrorOutputType::Json {
|
||||
pretty: false,
|
||||
json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never),
|
||||
};
|
||||
|
||||
// Reference
|
||||
v1.search_paths
|
||||
.push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("native=abc", JSON));
|
||||
v1.search_paths
|
||||
.push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("crate=def", JSON));
|
||||
v1.search_paths
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
|
||||
v1.search_paths
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", JSON));
|
||||
v1.search_paths
|
||||
.push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("all=mno", JSON));
|
||||
|
||||
v2.search_paths
|
||||
.push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("native=abc", JSON));
|
||||
v2.search_paths
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
|
||||
v2.search_paths
|
||||
.push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("crate=def", JSON));
|
||||
v2.search_paths
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", JSON));
|
||||
v2.search_paths
|
||||
.push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("all=mno", JSON));
|
||||
|
||||
v3.search_paths
|
||||
.push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("crate=def", JSON));
|
||||
v3.search_paths
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", JSON));
|
||||
v3.search_paths
|
||||
.push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("native=abc", JSON));
|
||||
v3.search_paths
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
|
||||
v3.search_paths
|
||||
.push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("all=mno", JSON));
|
||||
|
||||
v4.search_paths
|
||||
.push(SearchPath::from_cli_opt("all=mno", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("all=mno", JSON));
|
||||
v4.search_paths
|
||||
.push(SearchPath::from_cli_opt("native=abc", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("native=abc", JSON));
|
||||
v4.search_paths
|
||||
.push(SearchPath::from_cli_opt("crate=def", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("crate=def", JSON));
|
||||
v4.search_paths
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
|
||||
v4.search_paths
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", super::ErrorOutputType::Json(false)));
|
||||
.push(SearchPath::from_cli_opt("framework=jkl", JSON));
|
||||
|
||||
assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
|
||||
assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
|
||||
|
@ -1033,39 +1033,42 @@ fn default_emitter(
|
||||
emitter_dest: Option<Box<dyn Write + Send>>,
|
||||
) -> Box<dyn Emitter + sync::Send> {
|
||||
match (sopts.error_format, emitter_dest) {
|
||||
(config::ErrorOutputType::HumanReadable(color_config), None) => Box::new(
|
||||
EmitterWriter::stderr(
|
||||
color_config,
|
||||
Some(source_map.clone()),
|
||||
false,
|
||||
sopts.debugging_opts.teach,
|
||||
).ui_testing(sopts.debugging_opts.ui_testing),
|
||||
),
|
||||
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => Box::new(
|
||||
EmitterWriter::new(dst, Some(source_map.clone()), false, false)
|
||||
.ui_testing(sopts.debugging_opts.ui_testing),
|
||||
),
|
||||
(config::ErrorOutputType::Json(pretty), None) => Box::new(
|
||||
(config::ErrorOutputType::HumanReadable(kind), dst) => {
|
||||
let (short, color_config) = kind.unzip();
|
||||
let emitter = match dst {
|
||||
None => EmitterWriter::stderr(
|
||||
color_config,
|
||||
Some(source_map.clone()),
|
||||
short,
|
||||
sopts.debugging_opts.teach,
|
||||
),
|
||||
Some(dst) => EmitterWriter::new(
|
||||
dst,
|
||||
Some(source_map.clone()),
|
||||
short,
|
||||
false, // no teach messages when writing to a buffer
|
||||
false, // no colors when writing to a buffer
|
||||
),
|
||||
};
|
||||
Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
|
||||
},
|
||||
(config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
|
||||
JsonEmitter::stderr(
|
||||
Some(registry),
|
||||
source_map.clone(),
|
||||
pretty,
|
||||
json_rendered,
|
||||
).ui_testing(sopts.debugging_opts.ui_testing),
|
||||
),
|
||||
(config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new(
|
||||
(config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
|
||||
JsonEmitter::new(
|
||||
dst,
|
||||
Some(registry),
|
||||
source_map.clone(),
|
||||
pretty,
|
||||
json_rendered,
|
||||
).ui_testing(sopts.debugging_opts.ui_testing),
|
||||
),
|
||||
(config::ErrorOutputType::Short(color_config), None) => Box::new(
|
||||
EmitterWriter::stderr(color_config, Some(source_map.clone()), true, false),
|
||||
),
|
||||
(config::ErrorOutputType::Short(_), Some(dst)) => {
|
||||
Box::new(EmitterWriter::new(dst, Some(source_map.clone()), true, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1322,13 +1325,12 @@ pub enum IncrCompSession {
|
||||
|
||||
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
|
||||
let emitter: Box<dyn Emitter + sync::Send> = match output {
|
||||
config::ErrorOutputType::HumanReadable(color_config) => {
|
||||
Box::new(EmitterWriter::stderr(color_config, None, false, false))
|
||||
}
|
||||
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
|
||||
config::ErrorOutputType::Short(color_config) => {
|
||||
Box::new(EmitterWriter::stderr(color_config, None, true, false))
|
||||
config::ErrorOutputType::HumanReadable(kind) => {
|
||||
let (short, color_config) = kind.unzip();
|
||||
Box::new(EmitterWriter::stderr(color_config, None, short, false))
|
||||
}
|
||||
config::ErrorOutputType::Json { pretty, json_rendered } =>
|
||||
Box::new(JsonEmitter::basic(pretty, json_rendered)),
|
||||
};
|
||||
let handler = errors::Handler::with_emitter(true, None, emitter);
|
||||
handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
|
||||
@ -1337,13 +1339,12 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
|
||||
|
||||
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
|
||||
let emitter: Box<dyn Emitter + sync::Send> = match output {
|
||||
config::ErrorOutputType::HumanReadable(color_config) => {
|
||||
Box::new(EmitterWriter::stderr(color_config, None, false, false))
|
||||
}
|
||||
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
|
||||
config::ErrorOutputType::Short(color_config) => {
|
||||
Box::new(EmitterWriter::stderr(color_config, None, true, false))
|
||||
config::ErrorOutputType::HumanReadable(kind) => {
|
||||
let (short, color_config) = kind.unzip();
|
||||
Box::new(EmitterWriter::stderr(color_config, None, short, false))
|
||||
}
|
||||
config::ErrorOutputType::Json { pretty, json_rendered } =>
|
||||
Box::new(JsonEmitter::basic(pretty, json_rendered)),
|
||||
};
|
||||
let handler = errors::Handler::with_emitter(true, None, emitter);
|
||||
handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
|
||||
|
@ -16,9 +16,35 @@ use std::borrow::Cow;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::cmp::{min, Reverse};
|
||||
use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter};
|
||||
use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi};
|
||||
use termcolor::{WriteColor, Color, Buffer};
|
||||
|
||||
/// Describes the way the content of the `rendered` field of the json output is generated
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum HumanReadableErrorType {
|
||||
Default(ColorConfig),
|
||||
Short(ColorConfig),
|
||||
}
|
||||
|
||||
impl HumanReadableErrorType {
|
||||
/// Returns a (`short`, `color`) tuple
|
||||
pub fn unzip(self) -> (bool, ColorConfig) {
|
||||
match self {
|
||||
HumanReadableErrorType::Default(cc) => (false, cc),
|
||||
HumanReadableErrorType::Short(cc) => (true, cc),
|
||||
}
|
||||
}
|
||||
pub fn new_emitter(
|
||||
self,
|
||||
dst: Box<dyn Write + Send>,
|
||||
source_map: Option<Lrc<SourceMapperDyn>>,
|
||||
teach: bool,
|
||||
) -> EmitterWriter {
|
||||
let (short, color_config) = self.unzip();
|
||||
EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors())
|
||||
}
|
||||
}
|
||||
|
||||
const ANONYMIZED_LINE_NUM: &str = "LL";
|
||||
|
||||
/// Emitter trait for emitting errors.
|
||||
@ -104,8 +130,8 @@ pub enum ColorConfig {
|
||||
}
|
||||
|
||||
impl ColorConfig {
|
||||
fn to_color_choice(&self) -> ColorChoice {
|
||||
match *self {
|
||||
fn to_color_choice(self) -> ColorChoice {
|
||||
match self {
|
||||
ColorConfig::Always => {
|
||||
if atty::is(atty::Stream::Stderr) {
|
||||
ColorChoice::Always
|
||||
@ -120,6 +146,14 @@ impl ColorConfig {
|
||||
ColorConfig::Auto => ColorChoice::Never,
|
||||
}
|
||||
}
|
||||
fn suggests_using_colors(self) -> bool {
|
||||
match self {
|
||||
| ColorConfig::Always
|
||||
| ColorConfig::Auto
|
||||
=> true,
|
||||
ColorConfig::Never => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EmitterWriter {
|
||||
@ -152,13 +186,15 @@ impl EmitterWriter {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(dst: Box<dyn Write + Send>,
|
||||
source_map: Option<Lrc<SourceMapperDyn>>,
|
||||
short_message: bool,
|
||||
teach: bool)
|
||||
-> EmitterWriter {
|
||||
pub fn new(
|
||||
dst: Box<dyn Write + Send>,
|
||||
source_map: Option<Lrc<SourceMapperDyn>>,
|
||||
short_message: bool,
|
||||
teach: bool,
|
||||
colored: bool,
|
||||
) -> EmitterWriter {
|
||||
EmitterWriter {
|
||||
dst: Raw(dst),
|
||||
dst: Raw(dst, colored),
|
||||
sm: source_map,
|
||||
short_message,
|
||||
teach,
|
||||
@ -1538,13 +1574,15 @@ fn emit_to_destination(rendered_buffer: &[Vec<StyledString>],
|
||||
pub enum Destination {
|
||||
Terminal(StandardStream),
|
||||
Buffered(BufferWriter),
|
||||
Raw(Box<dyn Write + Send>),
|
||||
// The bool denotes whether we should be emitting ansi color codes or not
|
||||
Raw(Box<(dyn Write + Send)>, bool),
|
||||
}
|
||||
|
||||
pub enum WritableDst<'a> {
|
||||
Terminal(&'a mut StandardStream),
|
||||
Buffered(&'a mut BufferWriter, Buffer),
|
||||
Raw(&'a mut Box<dyn Write + Send>),
|
||||
Raw(&'a mut (dyn Write + Send)),
|
||||
ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
|
||||
}
|
||||
|
||||
impl Destination {
|
||||
@ -1570,7 +1608,8 @@ impl Destination {
|
||||
let buf = t.buffer();
|
||||
WritableDst::Buffered(t, buf)
|
||||
}
|
||||
Destination::Raw(ref mut t) => WritableDst::Raw(t),
|
||||
Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
|
||||
Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1628,6 +1667,7 @@ impl<'a> WritableDst<'a> {
|
||||
match *self {
|
||||
WritableDst::Terminal(ref mut t) => t.set_color(color),
|
||||
WritableDst::Buffered(_, ref mut t) => t.set_color(color),
|
||||
WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
|
||||
WritableDst::Raw(_) => Ok(())
|
||||
}
|
||||
}
|
||||
@ -1636,6 +1676,7 @@ impl<'a> WritableDst<'a> {
|
||||
match *self {
|
||||
WritableDst::Terminal(ref mut t) => t.reset(),
|
||||
WritableDst::Buffered(_, ref mut t) => t.reset(),
|
||||
WritableDst::ColoredRaw(ref mut t) => t.reset(),
|
||||
WritableDst::Raw(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
@ -1647,6 +1688,7 @@ impl<'a> Write for WritableDst<'a> {
|
||||
WritableDst::Terminal(ref mut t) => t.write(bytes),
|
||||
WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
|
||||
WritableDst::Raw(ref mut w) => w.write(bytes),
|
||||
WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1655,6 +1697,7 @@ impl<'a> Write for WritableDst<'a> {
|
||||
WritableDst::Terminal(ref mut t) => t.flush(),
|
||||
WritableDst::Buffered(_, ref mut buf) => buf.flush(),
|
||||
WritableDst::Raw(ref mut w) => w.flush(),
|
||||
WritableDst::ColoredRaw(ref mut w) => w.flush(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use rustc::hir::def::Def;
|
||||
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
|
||||
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
|
||||
use rustc::ty::layout::{self, LayoutOf, VariantIdx, Size};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::util::common::ErrorReported;
|
||||
@ -21,7 +21,7 @@ use syntax::ast::Mutability;
|
||||
use syntax::source_map::{Span, DUMMY_SP};
|
||||
|
||||
use crate::interpret::{self,
|
||||
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
|
||||
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar,
|
||||
RawConst, ConstValue,
|
||||
EvalResult, EvalError, InterpError, GlobalId, InterpretCx, StackPopCleanup,
|
||||
Allocation, AllocId, MemoryKind,
|
||||
@ -406,6 +406,15 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
||||
Cow::Borrowed(alloc)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn new_allocation(
|
||||
_size: Size,
|
||||
_extra: &Self::MemoryExtra,
|
||||
_kind: MemoryKind<!>,
|
||||
) -> (Self::AllocExtra, Self::PointerTag) {
|
||||
((), ())
|
||||
}
|
||||
|
||||
fn box_alloc(
|
||||
_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
|
||||
_dest: PlaceTy<'tcx>,
|
||||
@ -439,15 +448,6 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag_new_allocation(
|
||||
_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
|
||||
ptr: Pointer,
|
||||
_kind: MemoryKind<Self::MemoryKinds>,
|
||||
) -> Pointer {
|
||||
ptr
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn stack_push(
|
||||
_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
|
||||
|
@ -7,11 +7,11 @@ use std::hash::Hash;
|
||||
|
||||
use rustc::hir::{self, def_id::DefId};
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, query::TyCtxtAt};
|
||||
use rustc::ty::{self, query::TyCtxtAt, layout::Size};
|
||||
|
||||
use super::{
|
||||
Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
|
||||
InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
|
||||
InterpretCx, PlaceTy, MPlaceTy, OpTy, ImmTy, MemoryKind,
|
||||
};
|
||||
|
||||
/// Whether this kind of memory is allowed to leak
|
||||
@ -76,7 +76,7 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
||||
type MemoryExtra: Default;
|
||||
|
||||
/// Extra data stored in every allocation.
|
||||
type AllocExtra: AllocationExtra<Self::PointerTag, Self::MemoryExtra> + 'static;
|
||||
type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;
|
||||
|
||||
/// Memory's allocation map
|
||||
type MemoryMap:
|
||||
@ -139,18 +139,6 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
||||
memory_extra: &Self::MemoryExtra,
|
||||
) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag, Self::AllocExtra>>>;
|
||||
|
||||
/// Called to turn an allocation obtained from the `tcx` into one that has
|
||||
/// the right type for this machine.
|
||||
///
|
||||
/// This should avoid copying if no work has to be done! If this returns an owned
|
||||
/// allocation (because a copy had to be done to add tags or metadata), machine memory will
|
||||
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
|
||||
/// owned allocation to the map even when the map is shared.)
|
||||
fn adjust_static_allocation<'b>(
|
||||
alloc: &'b Allocation,
|
||||
memory_extra: &Self::MemoryExtra,
|
||||
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
|
||||
|
||||
/// Called for all binary operations on integer(-like) types when one operand is a pointer
|
||||
/// value, and for the `Offset` operation that is inherently about pointers.
|
||||
///
|
||||
@ -168,12 +156,24 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
|
||||
dest: PlaceTy<'tcx, Self::PointerTag>,
|
||||
) -> EvalResult<'tcx>;
|
||||
|
||||
/// Adds the tag for a newly allocated pointer.
|
||||
fn tag_new_allocation(
|
||||
ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
|
||||
ptr: Pointer,
|
||||
/// Called to turn an allocation obtained from the `tcx` into one that has
|
||||
/// the right type for this machine.
|
||||
///
|
||||
/// This should avoid copying if no work has to be done! If this returns an owned
|
||||
/// allocation (because a copy had to be done to add tags or metadata), machine memory will
|
||||
/// cache the result. (This relies on `AllocMap::get_or` being able to add the
|
||||
/// owned allocation to the map even when the map is shared.)
|
||||
fn adjust_static_allocation<'b>(
|
||||
alloc: &'b Allocation,
|
||||
memory_extra: &Self::MemoryExtra,
|
||||
) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
|
||||
|
||||
/// Computes the extra state and the tag for a new allocation.
|
||||
fn new_allocation(
|
||||
size: Size,
|
||||
extra: &Self::MemoryExtra,
|
||||
kind: MemoryKind<Self::MemoryKinds>,
|
||||
) -> Pointer<Self::PointerTag>;
|
||||
) -> (Self::AllocExtra, Self::PointerTag);
|
||||
|
||||
/// Executed when evaluating the `*` operator: Following a reference.
|
||||
/// This has the chance to adjust the tag. It should not change anything else!
|
||||
|
@ -132,9 +132,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||
size: Size,
|
||||
align: Align,
|
||||
kind: MemoryKind<M::MemoryKinds>,
|
||||
) -> Pointer {
|
||||
let extra = AllocationExtra::memory_allocated(size, &self.extra);
|
||||
Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind))
|
||||
) -> Pointer<M::PointerTag> {
|
||||
let (extra, tag) = M::new_allocation(size, &self.extra, kind);
|
||||
Pointer::from(self.allocate_with(Allocation::undef(size, align, extra), kind)).with_tag(tag)
|
||||
}
|
||||
|
||||
pub fn reallocate(
|
||||
@ -145,7 +145,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||
new_size: Size,
|
||||
new_align: Align,
|
||||
kind: MemoryKind<M::MemoryKinds>,
|
||||
) -> EvalResult<'tcx, Pointer> {
|
||||
) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
|
||||
if ptr.offset.bytes() != 0 {
|
||||
return err!(ReallocateNonBasePtr);
|
||||
}
|
||||
@ -156,7 +156,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
||||
self.copy(
|
||||
ptr.into(),
|
||||
old_align,
|
||||
new_ptr.with_default_tag().into(),
|
||||
new_ptr.into(),
|
||||
new_align,
|
||||
old_size.min(new_size),
|
||||
/*nonoverlapping*/ true,
|
||||
|
@ -31,19 +31,6 @@ pub enum Immediate<Tag=(), Id=AllocId> {
|
||||
ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
|
||||
}
|
||||
|
||||
impl Immediate {
|
||||
#[inline]
|
||||
pub fn with_default_tag<Tag>(self) -> Immediate<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
match self {
|
||||
Immediate::Scalar(x) => Immediate::Scalar(x.with_default_tag()),
|
||||
Immediate::ScalarPair(x, y) =>
|
||||
Immediate::ScalarPair(x.with_default_tag(), y.with_default_tag()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, Tag> Immediate<Tag> {
|
||||
#[inline]
|
||||
pub fn from_scalar(val: Scalar<Tag>) -> Self {
|
||||
@ -142,18 +129,6 @@ pub enum Operand<Tag=(), Id=AllocId> {
|
||||
Indirect(MemPlace<Tag, Id>),
|
||||
}
|
||||
|
||||
impl Operand {
|
||||
#[inline]
|
||||
pub fn with_default_tag<Tag>(self) -> Operand<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
match self {
|
||||
Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()),
|
||||
Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> Operand<Tag> {
|
||||
#[inline]
|
||||
pub fn erase_tag(self) -> Operand
|
||||
@ -554,16 +529,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
// We rely on mutability being set correctly in that allocation to prevent writes
|
||||
// where none should happen -- and for `static mut`, we copy on demand anyway.
|
||||
Operand::Indirect(
|
||||
MemPlace::from_ptr(ptr, alloc.align)
|
||||
).with_default_tag()
|
||||
MemPlace::from_ptr(ptr.with_default_tag(), alloc.align)
|
||||
)
|
||||
},
|
||||
ConstValue::Slice(a, b) =>
|
||||
Operand::Immediate(Immediate::ScalarPair(
|
||||
a.into(),
|
||||
Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(),
|
||||
)).with_default_tag(),
|
||||
a.with_default_tag().into(),
|
||||
Scalar::from_uint(b, self.tcx.data_layout.pointer_size)
|
||||
.with_default_tag().into(),
|
||||
)),
|
||||
ConstValue::Scalar(x) =>
|
||||
Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag(),
|
||||
Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())),
|
||||
ConstValue::Unevaluated(def_id, substs) => {
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
return Ok(OpTy::from(self.const_eval_raw(GlobalId {
|
||||
|
@ -83,23 +83,19 @@ impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
impl MemPlace {
|
||||
impl<Tag> MemPlace<Tag> {
|
||||
/// Replace ptr tag, maintain vtable tag (if any)
|
||||
#[inline]
|
||||
pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
|
||||
where Tag: Default
|
||||
{
|
||||
pub fn replace_tag(self, new_tag: Tag) -> Self {
|
||||
MemPlace {
|
||||
ptr: self.ptr.with_default_tag(),
|
||||
ptr: self.ptr.erase_tag().with_tag(new_tag),
|
||||
align: self.align,
|
||||
meta: self.meta.map(Scalar::with_default_tag),
|
||||
meta: self.meta,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> MemPlace<Tag> {
|
||||
#[inline]
|
||||
pub fn erase_tag(self) -> MemPlace
|
||||
{
|
||||
pub fn erase_tag(self) -> MemPlace {
|
||||
MemPlace {
|
||||
ptr: self.ptr.erase_tag(),
|
||||
align: self.align,
|
||||
@ -107,16 +103,6 @@ impl<Tag> MemPlace<Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_tag(self, new_tag: Tag) -> Self
|
||||
{
|
||||
MemPlace {
|
||||
ptr: self.ptr.with_tag(new_tag),
|
||||
align: self.align,
|
||||
meta: self.meta,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
|
||||
MemPlace {
|
||||
@ -189,11 +175,11 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace ptr tag, maintain vtable tag (if any)
|
||||
#[inline]
|
||||
pub fn with_tag(self, new_tag: Tag) -> Self
|
||||
{
|
||||
pub fn replace_tag(self, new_tag: Tag) -> Self {
|
||||
MPlaceTy {
|
||||
mplace: self.mplace.with_tag(new_tag),
|
||||
mplace: self.mplace.replace_tag(new_tag),
|
||||
layout: self.layout,
|
||||
}
|
||||
}
|
||||
@ -312,7 +298,7 @@ where
|
||||
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
|
||||
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
|
||||
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
|
||||
M::AllocExtra: AllocationExtra<Tag, M::MemoryExtra>,
|
||||
M::AllocExtra: AllocationExtra<Tag>,
|
||||
{
|
||||
/// Take a value, which represents a (thin or fat) reference, and make it a place.
|
||||
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
|
||||
@ -943,7 +929,6 @@ where
|
||||
let (size, align) = self.size_and_align_of(meta, local_layout)?
|
||||
.expect("Cannot allocate for non-dyn-sized type");
|
||||
let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
|
||||
let ptr = M::tag_new_allocation(self, ptr, MemoryKind::Stack);
|
||||
let mplace = MemPlace { ptr: ptr.into(), align, meta };
|
||||
if let Some(value) = old_val {
|
||||
// Preserve old value.
|
||||
@ -981,7 +966,6 @@ where
|
||||
kind: MemoryKind<M::MemoryKinds>,
|
||||
) -> MPlaceTy<'tcx, M::PointerTag> {
|
||||
let ptr = self.memory.allocate(layout.size, layout.align.abi, kind);
|
||||
let ptr = M::tag_new_allocation(self, ptr, kind);
|
||||
MPlaceTy::from_aligned_ptr(ptr, layout)
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
ptr_size * (3 + methods.len() as u64),
|
||||
ptr_align,
|
||||
MemoryKind::Vtable,
|
||||
).with_default_tag();
|
||||
);
|
||||
let tcx = &*self.tcx;
|
||||
|
||||
let drop = crate::monomorphize::resolve_drop_in_place(*tcx, ty);
|
||||
|
@ -326,7 +326,12 @@ fn check_terminator(
|
||||
abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
|
||||
abi::Abi::Rust => return Err((
|
||||
span,
|
||||
"can only call other `min_const_fn` within a `min_const_fn`".into(),
|
||||
format!(
|
||||
"can only call other `const fn` within a `const fn`, \
|
||||
but `{:?}` is not stable as `const fn`",
|
||||
func,
|
||||
)
|
||||
.into(),
|
||||
)),
|
||||
abi => return Err((
|
||||
span,
|
||||
|
@ -3,7 +3,7 @@ use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use errors;
|
||||
use errors::emitter::ColorConfig;
|
||||
use errors::emitter::{ColorConfig, HumanReadableErrorType};
|
||||
use getopts;
|
||||
use rustc::lint::Level;
|
||||
use rustc::session::early_error;
|
||||
@ -254,12 +254,19 @@ impl Options {
|
||||
(instead was `{}`)", arg));
|
||||
}
|
||||
};
|
||||
// FIXME: deduplicate this code from the identical code in librustc/session/config.rs
|
||||
let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
|
||||
Some("human") => ErrorOutputType::HumanReadable(color),
|
||||
Some("json") => ErrorOutputType::Json(false),
|
||||
Some("pretty-json") => ErrorOutputType::Json(true),
|
||||
Some("short") => ErrorOutputType::Short(color),
|
||||
None => ErrorOutputType::HumanReadable(color),
|
||||
None |
|
||||
Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
|
||||
Some("json") => ErrorOutputType::Json {
|
||||
pretty: false,
|
||||
json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
|
||||
},
|
||||
Some("pretty-json") => ErrorOutputType::Json {
|
||||
pretty: true,
|
||||
json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
|
||||
},
|
||||
Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
|
||||
Some(arg) => {
|
||||
early_error(ErrorOutputType::default(),
|
||||
&format!("argument for --error-format must be `human`, `json` or \
|
||||
|
@ -299,15 +299,18 @@ pub fn new_handler(error_format: ErrorOutputType,
|
||||
// stick to the defaults
|
||||
let sessopts = Options::default();
|
||||
let emitter: Box<dyn Emitter + sync::Send> = match error_format {
|
||||
ErrorOutputType::HumanReadable(color_config) => Box::new(
|
||||
EmitterWriter::stderr(
|
||||
color_config,
|
||||
source_map.map(|cm| cm as _),
|
||||
false,
|
||||
sessopts.debugging_opts.teach,
|
||||
).ui_testing(ui_testing)
|
||||
),
|
||||
ErrorOutputType::Json(pretty) => {
|
||||
ErrorOutputType::HumanReadable(kind) => {
|
||||
let (short, color_config) = kind.unzip();
|
||||
Box::new(
|
||||
EmitterWriter::stderr(
|
||||
color_config,
|
||||
source_map.map(|cm| cm as _),
|
||||
short,
|
||||
sessopts.debugging_opts.teach,
|
||||
).ui_testing(ui_testing)
|
||||
)
|
||||
},
|
||||
ErrorOutputType::Json { pretty, json_rendered } => {
|
||||
let source_map = source_map.unwrap_or_else(
|
||||
|| Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping())));
|
||||
Box::new(
|
||||
@ -315,16 +318,10 @@ pub fn new_handler(error_format: ErrorOutputType,
|
||||
None,
|
||||
source_map,
|
||||
pretty,
|
||||
json_rendered,
|
||||
).ui_testing(ui_testing)
|
||||
)
|
||||
},
|
||||
ErrorOutputType::Short(color_config) => Box::new(
|
||||
EmitterWriter::stderr(
|
||||
color_config,
|
||||
source_map.map(|cm| cm as _),
|
||||
true,
|
||||
false)
|
||||
),
|
||||
};
|
||||
|
||||
errors::Handler::with_emitter_and_flags(
|
||||
|
@ -381,7 +381,7 @@ pub fn make_test(s: &str,
|
||||
// Any errors in parsing should also appear when the doctest is compiled for real, so just
|
||||
// send all the errors that libsyntax emits directly into a `Sink` instead of stderr.
|
||||
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let emitter = EmitterWriter::new(box io::sink(), None, false, false);
|
||||
let emitter = EmitterWriter::new(box io::sink(), None, false, false, false);
|
||||
let handler = Handler::with_emitter(false, None, box emitter);
|
||||
let sess = ParseSess::with_span_handler(handler, cm);
|
||||
|
||||
|
@ -14,7 +14,7 @@ use crate::source_map::{SourceMap, FilePathMapping};
|
||||
use errors::registry::Registry;
|
||||
use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper};
|
||||
use errors::{DiagnosticId, Applicability};
|
||||
use errors::emitter::{Emitter, EmitterWriter};
|
||||
use errors::emitter::{Emitter, HumanReadableErrorType};
|
||||
|
||||
use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
@ -30,37 +30,46 @@ pub struct JsonEmitter {
|
||||
sm: Lrc<dyn SourceMapper + sync::Send + sync::Sync>,
|
||||
pretty: bool,
|
||||
ui_testing: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
}
|
||||
|
||||
impl JsonEmitter {
|
||||
pub fn stderr(registry: Option<Registry>,
|
||||
source_map: Lrc<SourceMap>,
|
||||
pretty: bool) -> JsonEmitter {
|
||||
pub fn stderr(
|
||||
registry: Option<Registry>,
|
||||
source_map: Lrc<SourceMap>,
|
||||
pretty: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
dst: Box::new(io::stderr()),
|
||||
registry,
|
||||
sm: source_map,
|
||||
pretty,
|
||||
ui_testing: false,
|
||||
json_rendered,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic(pretty: bool) -> JsonEmitter {
|
||||
pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter {
|
||||
let file_path_mapping = FilePathMapping::empty();
|
||||
JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)),
|
||||
pretty)
|
||||
pretty, json_rendered)
|
||||
}
|
||||
|
||||
pub fn new(dst: Box<dyn Write + Send>,
|
||||
registry: Option<Registry>,
|
||||
source_map: Lrc<SourceMap>,
|
||||
pretty: bool) -> JsonEmitter {
|
||||
pub fn new(
|
||||
dst: Box<dyn Write + Send>,
|
||||
registry: Option<Registry>,
|
||||
source_map: Lrc<SourceMap>,
|
||||
pretty: bool,
|
||||
json_rendered: HumanReadableErrorType,
|
||||
) -> JsonEmitter {
|
||||
JsonEmitter {
|
||||
dst,
|
||||
registry,
|
||||
sm: source_map,
|
||||
pretty,
|
||||
ui_testing: false,
|
||||
json_rendered,
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +199,7 @@ impl Diagnostic {
|
||||
}
|
||||
let buf = BufWriter::default();
|
||||
let output = buf.clone();
|
||||
EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false)
|
||||
je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false)
|
||||
.ui_testing(je.ui_testing).emit(db);
|
||||
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
|
||||
let output = String::from_utf8(output).unwrap();
|
||||
|
@ -1920,6 +1920,7 @@ mod tests {
|
||||
let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
|
||||
Some(sm.clone()),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
ParseSess {
|
||||
span_diagnostic: errors::Handler::with_emitter(true, None, Box::new(emitter)),
|
||||
|
@ -57,6 +57,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
|
||||
let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
|
||||
Some(source_map.clone()),
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
let handler = Handler::with_emitter(true, None, Box::new(emitter));
|
||||
handler.span_err(msp, "foo");
|
||||
|
@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
|
||||
const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
|
||||
|
||||
#[unstable(feature = "rust1", issue="0")]
|
||||
const fn foo2() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
|
||||
const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// conformity is required, even with `const_fn` feature gate
|
||||
@ -31,6 +31,6 @@ const fn foo2_gated() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
|
||||
const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_fn_libstd_stability.rs:15:25
|
||||
|
|
||||
LL | const fn bar() -> u32 { foo() }
|
||||
@ -6,7 +6,7 @@ LL | const fn bar() -> u32 { foo() }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_fn_libstd_stability.rs:22:26
|
||||
|
|
||||
LL | const fn bar2() -> u32 { foo2() }
|
||||
@ -22,7 +22,7 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_fn_libstd_stability.rs:34:32
|
||||
|
|
||||
LL | const fn bar2_gated() -> u32 { foo2_gated() }
|
||||
|
@ -12,14 +12,14 @@ const unsafe fn foo() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `min_const_fn`
|
||||
const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
|
||||
|
||||
#[unstable(feature = "rust1", issue="0")]
|
||||
const unsafe fn foo2() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `min_const_fn`
|
||||
const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// conformity is required, even with `const_fn` feature gate
|
||||
@ -31,6 +31,7 @@ const unsafe fn foo2_gated() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } //~ ERROR can only call other
|
||||
const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
||||
//~^ ERROR can only call other `const fn`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:15:41
|
||||
|
|
||||
LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
|
||||
@ -6,7 +6,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:22:42
|
||||
|
|
||||
LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
|
||||
@ -22,7 +22,7 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability.rs:34:48
|
||||
|
|
||||
LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
|
||||
|
@ -12,14 +12,14 @@ const fn foo() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `min_const_fn`
|
||||
const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
|
||||
|
||||
#[unstable(feature = "rust1", issue="0")]
|
||||
const fn foo2() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `min_const_fn`
|
||||
const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
|
||||
|
||||
// check whether this function cannot be called even with the feature gate active
|
||||
#[unstable(feature = "foo2", issue="0")]
|
||||
@ -27,6 +27,6 @@ const fn foo2_gated() -> u32 { 42 }
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// can't call non-min_const_fn
|
||||
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `min_const_fn`
|
||||
const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:15:32
|
||||
|
|
||||
LL | const unsafe fn bar() -> u32 { foo() }
|
||||
@ -6,7 +6,7 @@ LL | const unsafe fn bar() -> u32 { foo() }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:22:33
|
||||
|
|
||||
LL | const unsafe fn bar2() -> u32 { foo2() }
|
||||
@ -14,7 +14,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() }
|
||||
|
|
||||
= help: add #![feature(const_fn)] to the crate attributes to enable
|
||||
|
||||
error[E0723]: can only call other `min_const_fn` within a `min_const_fn` (see issue #57563)
|
||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn` (see issue #57563)
|
||||
--> $DIR/min_const_unsafe_fn_libstd_stability2.rs:30:39
|
||||
|
|
||||
LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
|
||||
|
@ -1,5 +1,6 @@
|
||||
// ignore-cloudabi
|
||||
// compile-flags: --error-format pretty-json -Zunstable-options
|
||||
// ignore-windows
|
||||
// compile-flags: --error-format pretty-json -Zunstable-options --json-rendered=termcolor
|
||||
|
||||
// The output for humans should just highlight the whole span without showing
|
||||
// the suggested replacement, but we also want to test that suggested
|
||||
|
@ -73,10 +73,10 @@ mod foo {
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 440,
|
||||
"byte_end": 444,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"byte_start": 484,
|
||||
"byte_end": 488,
|
||||
"line_start": 12,
|
||||
"line_end": 12,
|
||||
"column_start": 12,
|
||||
"column_end": 16,
|
||||
"is_primary": true,
|
||||
@ -101,10 +101,10 @@ mod foo {
|
||||
"spans": [
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -124,10 +124,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -147,10 +147,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -170,10 +170,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -193,10 +193,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -216,10 +216,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -239,10 +239,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -262,10 +262,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -285,10 +285,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -308,10 +308,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -331,10 +331,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -354,10 +354,10 @@ mod foo {
|
||||
},
|
||||
{
|
||||
"file_name": "$DIR/use_suggestion_json.rs",
|
||||
"byte_start": 417,
|
||||
"byte_end": 417,
|
||||
"line_start": 10,
|
||||
"line_end": 10,
|
||||
"byte_start": 461,
|
||||
"byte_end": 461,
|
||||
"line_start": 11,
|
||||
"line_end": 11,
|
||||
"column_start": 1,
|
||||
"column_end": 1,
|
||||
"is_primary": true,
|
||||
@ -380,22 +380,22 @@ mod foo {
|
||||
"rendered": null
|
||||
}
|
||||
],
|
||||
"rendered": "error[E0412]: cannot find type `Iter` in this scope
|
||||
--> $DIR/use_suggestion_json.rs:11:12
|
||||
|
|
||||
LL | let x: Iter;
|
||||
| ^^^^ not found in this scope
|
||||
help: possible candidates are found in other modules, you can import them into scope
|
||||
|
|
||||
LL | use std::collections::binary_heap::Iter;
|
||||
|
|
||||
LL | use std::collections::btree_map::Iter;
|
||||
|
|
||||
LL | use std::collections::btree_set::Iter;
|
||||
|
|
||||
LL | use std::collections::hash_map::Iter;
|
||||
|
|
||||
and 8 other candidates
|
||||
"rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: possible candidates are found in other modules, you can import them into scope\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_map::Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::btree_set::Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::hash_map::Iter;\u001b[0m
|
||||
\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m
|
||||
\u001b[0mand 8 other candidates\u001b[0m
|
||||
|
||||
"
|
||||
}
|
||||
@ -405,7 +405,7 @@ and 8 other candidates
|
||||
"level": "error",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": "error: aborting due to previous error
|
||||
"rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror\u001b[0m\u001b[0m\u001b[1m: aborting due to previous error\u001b[0m
|
||||
|
||||
"
|
||||
}
|
||||
@ -415,6 +415,6 @@ and 8 other candidates
|
||||
"level": "",
|
||||
"spans": [],
|
||||
"children": [],
|
||||
"rendered": "For more information about this error, try `rustc --explain E0412`.
|
||||
"rendered": "\u001b[0m\u001b[1mFor more information about this error, try `rustc --explain E0412`.\u001b[0m
|
||||
"
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ struct DiagnosticCode {
|
||||
explanation: Option<String>,
|
||||
}
|
||||
|
||||
pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
|
||||
pub fn extract_rendered(output: &str) -> String {
|
||||
output
|
||||
.lines()
|
||||
.filter_map(|line| {
|
||||
@ -70,11 +70,12 @@ pub fn extract_rendered(output: &str, proc_res: &ProcRes) -> String {
|
||||
match serde_json::from_str::<Diagnostic>(line) {
|
||||
Ok(diagnostic) => diagnostic.rendered,
|
||||
Err(error) => {
|
||||
proc_res.fatal(Some(&format!(
|
||||
print!(
|
||||
"failed to decode compiler output as json: \
|
||||
`{}`\nline: {}\noutput: {}",
|
||||
error, line, output
|
||||
)));
|
||||
);
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2090,50 +2090,10 @@ impl<'test> TestCx<'test> {
|
||||
}
|
||||
|
||||
fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
|
||||
self.try_print_open_handles();
|
||||
self.error(err);
|
||||
proc_res.fatal(None);
|
||||
}
|
||||
|
||||
// This function is a poor man's attempt to debug rust-lang/rust#38620, if
|
||||
// that's closed then this should be deleted
|
||||
//
|
||||
// This is a very "opportunistic" debugging attempt, so we ignore all
|
||||
// errors here.
|
||||
fn try_print_open_handles(&self) {
|
||||
if !cfg!(windows) {
|
||||
return;
|
||||
}
|
||||
if self.config.mode != Incremental {
|
||||
return;
|
||||
}
|
||||
|
||||
let filename = match self.testpaths.file.file_stem() {
|
||||
Some(path) => path,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let mut cmd = Command::new("handle.exe");
|
||||
cmd.arg("-a").arg("-u");
|
||||
cmd.arg(filename);
|
||||
cmd.arg("-nobanner");
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
let output = match cmd.spawn().and_then(read2_abbreviated) {
|
||||
Ok(output) => output,
|
||||
Err(_) => return,
|
||||
};
|
||||
println!("---------------------------------------------------");
|
||||
println!("ran extra command to debug rust-lang/rust#38620: ");
|
||||
println!("{:?}", cmd);
|
||||
println!("result: {}", output.status);
|
||||
println!("--- stdout ----------------------------------------");
|
||||
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||
println!("--- stderr ----------------------------------------");
|
||||
println!("{}", String::from_utf8_lossy(&output.stderr));
|
||||
println!("---------------------------------------------------");
|
||||
}
|
||||
|
||||
// codegen tests (using FileCheck)
|
||||
|
||||
fn compile_test_and_save_ir(&self) -> ProcRes {
|
||||
@ -2844,7 +2804,7 @@ impl<'test> TestCx<'test> {
|
||||
let stderr = if explicit {
|
||||
proc_res.stderr.clone()
|
||||
} else {
|
||||
json::extract_rendered(&proc_res.stderr, &proc_res)
|
||||
json::extract_rendered(&proc_res.stderr)
|
||||
};
|
||||
|
||||
let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
|
||||
@ -3464,7 +3424,9 @@ impl ProcRes {
|
||||
{}\n\
|
||||
------------------------------------------\n\
|
||||
\n",
|
||||
self.status, self.cmdline, self.stdout, self.stderr
|
||||
self.status, self.cmdline,
|
||||
json::extract_rendered(&self.stdout),
|
||||
json::extract_rendered(&self.stderr),
|
||||
);
|
||||
// Use resume_unwind instead of panic!() to prevent a panic message + backtrace from
|
||||
// compiletest, which is unnecessary noise.
|
||||
|
Loading…
Reference in New Issue
Block a user