1
Fork 0

Auto merge of #99024 - matthiaskrgr:rollup-8ygpcpg, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #97917 (Implement ExitCodeExt for Windows)
 - #98844 (Reword comments and rename HIR visiting methods.)
 - #98979 (interpret: use AllocRange in UninitByteAccess)
 - #98986 (Fix missing word in comment)
 - #98994 (replace process exit with more detailed exit in src/bootstrap/*.rs)
 - #98995 (Add a test for #80471)
 - #99002 (suggest adding a derive for #[default] applied to variants)
 - #99004 (Add a test for #70408)
 - #99017 (Replace boolean argument for print_where_clause with an enum to make code more clear)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-07-07 20:55:34 +00:00
commit 1517f5de01
47 changed files with 343 additions and 236 deletions

View file

@ -427,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
err_ub!(DanglingIntPointer(0, _)) => err_ub!(DanglingIntPointer(0, _)) =>
{ "a null {kind}" }, { "a null {kind}" },
err_ub!(DanglingIntPointer(i, _)) => err_ub!(DanglingIntPointer(i, _)) =>
{ "a dangling {kind} (address 0x{i:x} is unallocated)" }, { "a dangling {kind} (address {i:#x} is unallocated)" },
err_ub!(PointerOutOfBounds { .. }) => err_ub!(PointerOutOfBounds { .. }) =>
{ "a dangling {kind} (going beyond the bounds of its allocation)" }, { "a dangling {kind} (going beyond the bounds of its allocation)" },
// This cannot happen during const-eval (because interning already detects // This cannot happen during const-eval (because interning already detects
@ -941,7 +941,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// element that byte belongs to so we can // element that byte belongs to so we can
// provide an index. // provide an index.
let i = usize::try_from( let i = usize::try_from(
access.uninit_offset.bytes() / layout.size.bytes(), access.uninit.start.bytes() / layout.size.bytes(),
) )
.unwrap(); .unwrap();
self.path.push(PathElem::ArrayElem(i)); self.path.push(PathElem::ArrayElem(i));

View file

@ -19,7 +19,7 @@
//! - Example: Examine each expression to look for its type and do some check or other. //! - Example: Examine each expression to look for its type and do some check or other.
//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to //! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
//! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use //! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
//! `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your //! `tcx.hir().visit_all_item_likes_in_crate(&mut visitor)`. Within your
//! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke //! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
//! `intravisit::walk_expr()` to keep walking the subparts). //! `intravisit::walk_expr()` to keep walking the subparts).
//! - Pro: Visitor methods for any kind of HIR node, not just item-like things. //! - Pro: Visitor methods for any kind of HIR node, not just item-like things.
@ -190,7 +190,7 @@ use nested_filter::NestedFilter;
/// (this is why the module is called `intravisit`, to distinguish it /// (this is why the module is called `intravisit`, to distinguish it
/// from the AST's `visit` module, which acts differently). If you /// from the AST's `visit` module, which acts differently). If you
/// simply want to visit all items in the crate in some order, you /// simply want to visit all items in the crate in some order, you
/// should call `Crate::visit_all_items`. Otherwise, see the comment /// should call `tcx.hir().visit_all_item_likes_in_crate`. Otherwise, see the comment
/// on `visit_nested_item` for details on how to visit nested items. /// on `visit_nested_item` for details on how to visit nested items.
/// ///
/// If you want to ensure that your code handles every variant /// If you want to ensure that your code handles every variant

View file

@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
let mut visitor = let mut visitor =
IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
visitor.process_attrs(hir::CRATE_HIR_ID); visitor.process_attrs(hir::CRATE_HIR_ID);
tcx.hir().deep_visit_all_item_likes(&mut visitor); tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
(visitor.if_this_changed, visitor.then_this_would_need) (visitor.if_this_changed, visitor.then_this_would_need)
}; };

View file

@ -419,7 +419,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
return; return;
} }
self.tcx.hir().deep_visit_all_item_likes(self); self.tcx.hir().visit_all_item_likes_in_crate(self);
} }
fn encode_def_path_table(&mut self) { fn encode_def_path_table(&mut self) {

View file

@ -561,7 +561,7 @@ impl<'hir> Map<'hir> {
} }
} }
/// Walks the contents of a crate. See also `Crate::visit_all_items`. /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) { pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID); let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID);
visitor.visit_mod(top_mod, span, hir_id); visitor.visit_mod(top_mod, span, hir_id);
@ -581,53 +581,61 @@ impl<'hir> Map<'hir> {
} }
} }
/// Visits all items in the crate in some deterministic (but /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
/// unspecified) order. If you need to process every item, /// need to process every item-like, and don't care about visiting nested items in a particular
/// and care about nesting -- usually because your algorithm /// order then this method is the best choice. If you do care about this nesting, you should
/// follows lexical scoping rules -- then this method is the best choice. /// use the `tcx.hir().walk_toplevel_module`.
/// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query ///
/// or `items()` instead. /// Note that this function will access HIR for all the item-likes in the crate. If you only
/// need to access some of them, it is usually better to manually loop on the iterators
/// provided by `tcx.hir_crate_items(())`.
/// ///
/// Please see the notes in `intravisit.rs` for more information. /// Please see the notes in `intravisit.rs` for more information.
pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V) pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V)
where where
V: Visitor<'hir>, V: Visitor<'hir>,
{ {
let krate = self.krate(); let krate = self.tcx.hir_crate_items(());
for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
match owner.node() { for id in krate.items() {
OwnerNode::Item(item) => visitor.visit_item(item), visitor.visit_item(self.item(id));
OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), }
OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), for id in krate.trait_items() {
OwnerNode::Crate(_) => {} visitor.visit_trait_item(self.trait_item(id));
} }
for id in krate.impl_items() {
visitor.visit_impl_item(self.impl_item(id));
}
for id in krate.foreign_items() {
visitor.visit_foreign_item(self.foreign_item(id));
} }
} }
/// If you don't care about nesting, you should use the /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
/// `tcx.hir_module_items()` query or `module_items()` instead. /// item-likes in a single module.
/// Please see notes in `deep_visit_all_item_likes`. pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
where where
V: Visitor<'hir>, V: Visitor<'hir>,
{ {
let module = self.tcx.hir_module_items(module); let module = self.tcx.hir_module_items(module);
for id in module.items.iter() { for id in module.items() {
visitor.visit_item(self.item(*id)); visitor.visit_item(self.item(id));
} }
for id in module.trait_items.iter() { for id in module.trait_items() {
visitor.visit_trait_item(self.trait_item(*id)); visitor.visit_trait_item(self.trait_item(id));
} }
for id in module.impl_items.iter() { for id in module.impl_items() {
visitor.visit_impl_item(self.impl_item(*id)); visitor.visit_impl_item(self.impl_item(id));
} }
for id in module.foreign_items.iter() { for id in module.foreign_items() {
visitor.visit_foreign_item(self.foreign_item(*id)); visitor.visit_foreign_item(self.foreign_item(id));
} }
} }

View file

@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`. /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
/// ///
/// **This is the most common choice.** A very common pattern is /// **This is the most common choice.** A very common pattern is
/// to use `deep_visit_all_item_likes()` as an outer loop, /// to use `visit_all_item_likes_in_crate()` as an outer loop,
/// and to have the visitor that visits the contents of each item /// and to have the visitor that visits the contents of each item
/// using this setting. /// using this setting.
pub struct OnlyBodies(()); pub struct OnlyBodies(());

View file

@ -179,6 +179,11 @@ pub fn alloc_range(start: Size, size: Size) -> AllocRange {
} }
impl AllocRange { impl AllocRange {
#[inline]
pub fn from(r: Range<Size>) -> Self {
alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
}
#[inline(always)] #[inline(always)]
pub fn end(self) -> Size { pub fn end(self) -> Size {
self.start + self.size // This does overflow checking. self.start + self.size // This does overflow checking.
@ -1095,9 +1100,9 @@ impl InitMask {
/// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
/// indexes for the first contiguous span of the uninitialized access. /// indexes for the first contiguous span of the uninitialized access.
#[inline] #[inline]
pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> { pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> {
if end > self.len { if end > self.len {
return Err(self.len..end); return Err(AllocRange::from(self.len..end));
} }
let uninit_start = self.find_bit(start, end, false); let uninit_start = self.find_bit(start, end, false);
@ -1105,7 +1110,7 @@ impl InitMask {
match uninit_start { match uninit_start {
Some(uninit_start) => { Some(uninit_start) => {
let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end); let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
Err(uninit_start..uninit_end) Err(AllocRange::from(uninit_start..uninit_end))
} }
None => Ok(()), None => Ok(()),
} }
@ -1176,19 +1181,17 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
/// ///
/// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
/// indexes of the first contiguous uninitialized access. /// indexes of the first contiguous uninitialized access.
fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> { fn is_init(&self, range: AllocRange) -> Result<(), AllocRange> {
self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
} }
/// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
/// error which will report the first range of bytes which is uninitialized. /// error which will report the first range of bytes which is uninitialized.
fn check_init(&self, range: AllocRange) -> AllocResult { fn check_init(&self, range: AllocRange) -> AllocResult {
self.is_init(range).map_err(|idx_range| { self.is_init(range).map_err(|uninit_range| {
AllocError::InvalidUninitBytes(Some(UninitBytesAccess { AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
access_offset: range.start, access: range,
access_size: range.size, uninit: uninit_range,
uninit_offset: idx_range.start,
uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
})) }))
}) })
} }

View file

@ -1,4 +1,4 @@
use super::{AllocId, ConstAlloc, Pointer, Scalar}; use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
use crate::mir::interpret::ConstValue; use crate::mir::interpret::ConstValue;
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
@ -162,9 +162,9 @@ impl fmt::Display for InvalidProgramInfo<'_> {
AlreadyReported(ErrorGuaranteed { .. }) => { AlreadyReported(ErrorGuaranteed { .. }) => {
write!(f, "encountered constants with type errors, stopping evaluation") write!(f, "encountered constants with type errors, stopping evaluation")
} }
Layout(ref err) => write!(f, "{}", err), Layout(ref err) => write!(f, "{err}"),
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err), FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty), SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
} }
} }
} }
@ -205,14 +205,10 @@ impl fmt::Display for CheckInAllocMsg {
/// Details of an access to uninitialized bytes where it is not allowed. /// Details of an access to uninitialized bytes where it is not allowed.
#[derive(Debug)] #[derive(Debug)]
pub struct UninitBytesAccess { pub struct UninitBytesAccess {
/// Location of the original memory access. /// Range of the original memory access.
pub access_offset: Size, pub access: AllocRange,
/// Size of the original memory access. /// Range of the uninit memory that was encountered. (Might not be maximal.)
pub access_size: Size, pub uninit: AllocRange,
/// Location of the first uninitialized byte that was accessed.
pub uninit_offset: Size,
/// Number of consecutive uninitialized bytes that were accessed.
pub uninit_size: Size,
} }
/// Information about a size mismatch. /// Information about a size mismatch.
@ -308,30 +304,28 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UndefinedBehaviorInfo::*; use UndefinedBehaviorInfo::*;
match self { match self {
Ub(msg) => write!(f, "{}", msg), Ub(msg) => write!(f, "{msg}"),
Unreachable => write!(f, "entering unreachable code"), Unreachable => write!(f, "entering unreachable code"),
BoundsCheckFailed { ref len, ref index } => { BoundsCheckFailed { ref len, ref index } => {
write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index) write!(f, "indexing out of bounds: the len is {len} but the index is {index}")
} }
DivisionByZero => write!(f, "dividing by zero"), DivisionByZero => write!(f, "dividing by zero"),
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"), DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
InvalidVtableDropFn(sig) => write!( InvalidVtableDropFn(sig) => write!(
f, f,
"invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type",
sig
), ),
InvalidVtableSize => { InvalidVtableSize => {
write!(f, "invalid vtable: size is bigger than largest supported object") write!(f, "invalid vtable: size is bigger than largest supported object")
} }
InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg), InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"),
UnterminatedCString(p) => write!( UnterminatedCString(p) => write!(
f, f,
"reading a null-terminated string starting at {:?} with no null found before end of allocation", "reading a null-terminated string starting at {p:?} with no null found before end of allocation",
p,
), ),
PointerUseAfterFree(a) => { PointerUseAfterFree(a) => {
write!(f, "pointer to {a:?} was dereferenced after this allocation got freed") write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
@ -359,41 +353,36 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
} }
AlignmentCheckFailed { required, has } => write!( AlignmentCheckFailed { required, has } => write!(
f, f,
"accessing memory with alignment {}, but alignment {} is required", "accessing memory with alignment {has}, but alignment {required} is required",
has.bytes(), has = has.bytes(),
required.bytes() required = required.bytes()
), ),
WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"), WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"), DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
ValidationFailure { path: None, msg } => { ValidationFailure { path: None, msg } => {
write!(f, "constructing invalid value: {}", msg) write!(f, "constructing invalid value: {msg}")
} }
ValidationFailure { path: Some(path), msg } => { ValidationFailure { path: Some(path), msg } => {
write!(f, "constructing invalid value at {}: {}", path, msg) write!(f, "constructing invalid value at {path}: {msg}")
} }
InvalidBool(b) => { InvalidBool(b) => {
write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b) write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}")
} }
InvalidChar(c) => { InvalidChar(c) => {
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c) write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}")
} }
InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val), InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"),
InvalidFunctionPointer(p) => { InvalidFunctionPointer(p) => {
write!(f, "using {:?} as function pointer but it does not point to a function", p) write!(f, "using {p:?} as function pointer but it does not point to a function")
} }
InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
InvalidUninitBytes(Some((alloc, access))) => write!( InvalidUninitBytes(Some((alloc, info))) => write!(
f, f,
"reading {} byte{} of memory starting at {:?}, \ "reading memory at {alloc:?}{access:?}, \
but {} byte{} {} uninitialized starting at {:?}, \ but memory is uninitialized at {uninit:?}, \
and this operation requires initialized memory", and this operation requires initialized memory",
access.access_size.bytes(), access = info.access,
pluralize!(access.access_size.bytes()), uninit = info.uninit,
Pointer::new(*alloc, access.access_offset),
access.uninit_size.bytes(),
pluralize!(access.uninit_size.bytes()),
pluralize!("is", access.uninit_size.bytes()),
Pointer::new(*alloc, access.uninit_offset),
), ),
InvalidUninitBytes(None) => write!( InvalidUninitBytes(None) => write!(
f, f,
@ -402,8 +391,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
DeadLocal => write!(f, "accessing a dead local variable"), DeadLocal => write!(f, "accessing a dead local variable"),
ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!( ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
f, f,
"scalar size mismatch: expected {} bytes but got {} bytes instead", "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead",
target_size, data_size
), ),
UninhabitedEnumVariantWritten => { UninhabitedEnumVariantWritten => {
write!(f, "writing discriminant of an uninhabited enum") write!(f, "writing discriminant of an uninhabited enum")
@ -437,13 +425,13 @@ impl fmt::Display for UnsupportedOpInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UnsupportedOpInfo::*; use UnsupportedOpInfo::*;
match self { match self {
Unsupported(ref msg) => write!(f, "{}", msg), Unsupported(ref msg) => write!(f, "{msg}"),
ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"), ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
PartialPointerOverwrite(ptr) => { PartialPointerOverwrite(ptr) => {
write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr) write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}")
} }
ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did), ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"),
ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did), ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"),
} }
} }
} }
@ -526,11 +514,11 @@ impl fmt::Display for InterpError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InterpError::*; use InterpError::*;
match *self { match *self {
Unsupported(ref msg) => write!(f, "{}", msg), Unsupported(ref msg) => write!(f, "{msg}"),
InvalidProgram(ref msg) => write!(f, "{}", msg), InvalidProgram(ref msg) => write!(f, "{msg}"),
UndefinedBehavior(ref msg) => write!(f, "{}", msg), UndefinedBehavior(ref msg) => write!(f, "{msg}"),
ResourceExhaustion(ref msg) => write!(f, "{}", msg), ResourceExhaustion(ref msg) => write!(f, "{msg}"),
MachineStop(ref msg) => write!(f, "{}", msg), MachineStop(ref msg) => write!(f, "{msg}"),
} }
} }
} }

View file

@ -153,7 +153,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
_: &mir::Statement<'tcx>, _: &mir::Statement<'tcx>,
loc: Location, loc: Location,
) { ) {
// If we move from a place then only stops needing storage *after* // If we move from a place then it only stops needing storage *after*
// that statement. // that statement.
self.check_for_move(trans, loc); self.check_for_move(trans, loc);
} }

View file

@ -173,7 +173,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
intravisit::walk_struct_def(self, v) intravisit::walk_struct_def(self, v)
} }
} }
tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }); tcx.hir().visit_all_item_likes_in_crate(&mut GatherCtors { tcx, set: &mut set });
set set
} }

View file

@ -2428,7 +2428,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let check_attr_visitor = &mut CheckAttrVisitor { tcx }; let check_attr_visitor = &mut CheckAttrVisitor { tcx };
tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor); tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
if module_def_id.is_top_level_module() { if module_def_id.is_top_level_module() {
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());

View file

@ -56,7 +56,7 @@ impl NonConstExpr {
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let mut vis = CheckConstVisitor::new(tcx); let mut vis = CheckConstVisitor::new(tcx);
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis); tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis);
} }
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {

View file

@ -28,7 +28,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
errors: &errors, errors: &errors,
}; };
tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v); tcx.hir().visit_item_likes_in_module(module_id, &mut v);
}); });
let errors = errors.into_inner(); let errors = errors.into_inner();

View file

@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
} }
fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx)); tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
} }
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {

View file

@ -31,7 +31,7 @@ struct CheckLoopVisitor<'a, 'hir> {
} }
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module( tcx.hir().visit_item_likes_in_module(
module_def_id, module_def_id,
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }, &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
); );

View file

@ -14,7 +14,7 @@ use rustc_span::Span;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx }); tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
} }
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {

View file

@ -660,7 +660,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
/// Cross-references the feature names of unstable APIs with enabled /// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors. /// features and possibly prints errors.
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx }); tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
} }
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {
@ -890,7 +890,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let mut missing = MissingStabilityAnnotations { tcx, access_levels }; let mut missing = MissingStabilityAnnotations { tcx, access_levels };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing); tcx.hir().walk_toplevel_module(&mut missing);
tcx.hir().deep_visit_all_item_likes(&mut missing); tcx.hir().visit_all_item_likes_in_crate(&mut missing);
} }
let declared_lang_features = &tcx.features().declared_lang_features; let declared_lang_features = &tcx.features().declared_lang_features;

View file

@ -1499,10 +1499,16 @@ impl<'a> Resolver<'a> {
&& let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
&& let Some(span) = self.opt_span(def_id) && let Some(span) = self.opt_span(def_id)
{ {
err.span_help( let source_map = self.session.source_map();
self.session.source_map().guess_head_span(span), let head_span = source_map.guess_head_span(span);
"consider adding `#[derive(Default)]` to this enum", if let Ok(head) = source_map.span_to_snippet(head_span) {
); err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect);
} else {
err.span_help(
head_span,
"consider adding `#[derive(Default)]` to this enum",
);
}
} }
for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(

View file

@ -59,7 +59,7 @@ struct OnlySelfBounds(bool);
// Main entry point // Main entry point
fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx }); tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
} }
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {

View file

@ -234,3 +234,26 @@ impl ChildExt for process::Child {
self.handle.main_thread_handle() self.handle.main_thread_handle()
} }
} }
/// Windows-specific extensions to [`process::ExitCode`].
///
/// This trait is sealed: it cannot be implemented outside the standard library.
/// This is so that future additional methods are not breaking changes.
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
pub trait ExitCodeExt: Sealed {
/// Creates a new `ExitCode` from the raw underlying `u32` return value of
/// a process.
///
/// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
/// macro returned from the `GetExitCodeProcess` function to signal that the
/// process has yet to run to completion.
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
fn from_raw(raw: u32) -> Self;
}
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
impl ExitCodeExt for process::ExitCode {
fn from_raw(raw: u32) -> Self {
process::ExitCode::from_inner(From::from(raw))
}
}

View file

@ -1724,6 +1724,10 @@ impl crate::error::Error for ExitStatusError {}
#[stable(feature = "process_exitcode", since = "1.61.0")] #[stable(feature = "process_exitcode", since = "1.61.0")]
pub struct ExitCode(imp::ExitCode); pub struct ExitCode(imp::ExitCode);
/// Allows extension traits within `std`.
#[unstable(feature = "sealed", issue = "none")]
impl crate::sealed::Sealed for ExitCode {}
#[stable(feature = "process_exitcode", since = "1.61.0")] #[stable(feature = "process_exitcode", since = "1.61.0")]
impl ExitCode { impl ExitCode {
/// The canonical `ExitCode` for successful termination on this platform. /// The canonical `ExitCode` for successful termination on this platform.
@ -1814,6 +1818,18 @@ impl From<u8> for ExitCode {
} }
} }
impl AsInner<imp::ExitCode> for ExitCode {
fn as_inner(&self) -> &imp::ExitCode {
&self.0
}
}
impl FromInner<imp::ExitCode> for ExitCode {
fn from_inner(s: imp::ExitCode) -> ExitCode {
ExitCode(s)
}
}
impl Child { impl Child {
/// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
/// error is returned. /// error is returned.

View file

@ -707,6 +707,12 @@ impl From<u8> for ExitCode {
} }
} }
impl From<u32> for ExitCode {
fn from(code: u32) -> Self {
ExitCode(c::DWORD::from(code))
}
}
fn zeroed_startupinfo() -> c::STARTUPINFO { fn zeroed_startupinfo() -> c::STARTUPINFO {
c::STARTUPINFO { c::STARTUPINFO {
cb: 0, cb: 0,

View file

@ -346,11 +346,7 @@ impl StepDescription {
eprintln!( eprintln!(
"note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`" "note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`"
); );
#[cfg(not(test))] crate::detail_exit(1);
std::process::exit(1);
#[cfg(test)]
// so we can use #[should_panic]
panic!()
} }
} }
} }
@ -1008,7 +1004,7 @@ impl<'a> Builder<'a> {
if !help_on_error.is_empty() { if !help_on_error.is_empty() {
eprintln!("{}", help_on_error); eprintln!("{}", help_on_error);
} }
std::process::exit(1); crate::detail_exit(1);
} }
} }
@ -1437,7 +1433,7 @@ impl<'a> Builder<'a> {
"error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component" "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component"
); );
eprintln!("help: try `rustup component add clippy`"); eprintln!("help: try `rustup component add clippy`");
std::process::exit(1); crate::detail_exit(1);
}); });
if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") { if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") {
rustflags.arg("--cfg=bootstrap"); rustflags.arg("--cfg=bootstrap");

View file

@ -13,7 +13,7 @@ use std::fs;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufReader; use std::io::BufReader;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio}; use std::process::{Command, Stdio};
use std::str; use std::str;
use serde::Deserialize; use serde::Deserialize;
@ -1377,7 +1377,7 @@ pub fn run_cargo(
}); });
if !ok { if !ok {
exit(1); crate::detail_exit(1);
} }
// Ok now we need to actually find all the files listed in `toplevel`. We've // Ok now we need to actually find all the files listed in `toplevel`. We've

View file

@ -11,7 +11,7 @@ use std::ffi::OsStr;
use std::fmt; use std::fmt;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{exit, Command}; use std::process::Command;
use std::str::FromStr; use std::str::FromStr;
use crate::builder::{Builder, TaskPath}; use crate::builder::{Builder, TaskPath};
@ -805,8 +805,6 @@ impl Config {
let get_toml = |_| TomlConfig::default(); let get_toml = |_| TomlConfig::default();
#[cfg(not(test))] #[cfg(not(test))]
let get_toml = |file: &Path| { let get_toml = |file: &Path| {
use std::process;
let contents = let contents =
t!(fs::read_to_string(file), format!("config file {} not found", file.display())); t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
@ -817,7 +815,7 @@ impl Config {
Ok(table) => table, Ok(table) => table,
Err(err) => { Err(err) => {
eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err); eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
process::exit(2); crate::detail_exit(2);
} }
} }
}; };
@ -1487,7 +1485,7 @@ fn download_ci_rustc_commit(
println!("help: maybe your repository history is too shallow?"); println!("help: maybe your repository history is too shallow?");
println!("help: consider disabling `download-rustc`"); println!("help: consider disabling `download-rustc`");
println!("help: or fetch enough history to include one upstream commit"); println!("help: or fetch enough history to include one upstream commit");
exit(1); crate::detail_exit(1);
} }
// Warn if there were changes to the compiler or standard library since the ancestor commit. // Warn if there were changes to the compiler or standard library since the ancestor commit.

View file

@ -4,7 +4,6 @@
//! has various flags to configure how it's run. //! has various flags to configure how it's run.
use std::path::PathBuf; use std::path::PathBuf;
use std::process;
use getopts::Options; use getopts::Options;
@ -261,7 +260,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
// subcommand. // subcommand.
println!("{}\n", subcommand_help); println!("{}\n", subcommand_help);
let exit_code = if args.is_empty() { 0 } else { 1 }; let exit_code = if args.is_empty() { 0 } else { 1 };
process::exit(exit_code); crate::detail_exit(exit_code);
} }
}; };
@ -347,7 +346,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
} else if verbose { } else if verbose {
panic!("No paths available for subcommand `{}`", subcommand.as_str()); panic!("No paths available for subcommand `{}`", subcommand.as_str());
} }
process::exit(exit_code); crate::detail_exit(exit_code);
}; };
// Done specifying what options are possible, so do the getopts parsing // Done specifying what options are possible, so do the getopts parsing
@ -379,7 +378,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
"Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
You may need to move some options to after the subcommand.\n" You may need to move some options to after the subcommand.\n"
); );
process::exit(1); crate::detail_exit(1);
} }
// Extra help text for some commands // Extra help text for some commands
match subcommand { match subcommand {
@ -600,7 +599,7 @@ Arguments:
eprintln!("error: {}", err); eprintln!("error: {}", err);
eprintln!("help: the available profiles are:"); eprintln!("help: the available profiles are:");
eprint!("{}", Profile::all_for_help("- ")); eprint!("{}", Profile::all_for_help("- "));
std::process::exit(1); crate::detail_exit(1);
}) })
} else { } else {
t!(crate::setup::interactive_path()) t!(crate::setup::interactive_path())
@ -614,7 +613,7 @@ Arguments:
|| matches.opt_str("keep-stage-std").is_some() || matches.opt_str("keep-stage-std").is_some()
{ {
eprintln!("--keep-stage not yet supported for x.py check"); eprintln!("--keep-stage not yet supported for x.py check");
process::exit(1); crate::detail_exit(1);
} }
} }
@ -805,7 +804,7 @@ fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
Some("warn") => Some(false), Some("warn") => Some(false),
Some(value) => { Some(value) => {
eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,); eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,);
process::exit(1); crate::detail_exit(1);
} }
None => None, None => None,
} }

View file

@ -32,7 +32,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
code, run `./x.py fmt` instead.", code, run `./x.py fmt` instead.",
cmd_debug, cmd_debug,
); );
std::process::exit(1); crate::detail_exit(1);
} }
} }
} }
@ -114,7 +114,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| { let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
eprintln!("./x.py fmt is not supported on this channel"); eprintln!("./x.py fmt is not supported on this channel");
std::process::exit(1); crate::detail_exit(1);
}); });
assert!(rustfmt_path.exists(), "{}", rustfmt_path.display()); assert!(rustfmt_path.exists(), "{}", rustfmt_path.display());
let src = build.src.clone(); let src = build.src.clone();

View file

@ -109,7 +109,7 @@ use std::env;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{self, Command}; use std::process::Command;
use std::str; use std::str;
use filetime::FileTime; use filetime::FileTime;
@ -711,7 +711,7 @@ impl Build {
for failure in failures.iter() { for failure in failures.iter() {
eprintln!(" - {}\n", failure); eprintln!(" - {}\n", failure);
} }
process::exit(1); detail_exit(1);
} }
#[cfg(feature = "build-metrics")] #[cfg(feature = "build-metrics")]
@ -1617,7 +1617,7 @@ Alternatively, set `download-ci-llvm = true` in that `[llvm]` section
to download LLVM rather than building it. to download LLVM rather than building it.
" "
); );
std::process::exit(1); detail_exit(1);
} }
} }
@ -1646,6 +1646,20 @@ fn chmod(path: &Path, perms: u32) {
#[cfg(windows)] #[cfg(windows)]
fn chmod(_path: &Path, _perms: u32) {} fn chmod(_path: &Path, _perms: u32) {}
/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
/// If the test is running and code is an error code, it will cause a panic.
fn detail_exit(code: i32) -> ! {
// Successful exit
if code == 0 {
std::process::exit(0);
}
if cfg!(test) {
panic!("status code: {}", code);
} else {
std::panic::resume_unwind(Box::new(code));
}
}
impl Compiler { impl Compiler {
pub fn with_stage(mut self, stage: u32) -> Compiler { pub fn with_stage(mut self, stage: u32) -> Compiler {
self.stage = stage; self.stage = stage;

View file

@ -104,7 +104,7 @@ You should install cmake, or set `download-ci-llvm = true` in the
than building it. than building it.
" "
); );
std::process::exit(1); crate::detail_exit(1);
} }
} }

View file

@ -94,7 +94,7 @@ pub fn setup(config: &Config, profile: Profile) {
"note: this will use the configuration in {}", "note: this will use the configuration in {}",
profile.include_path(&config.src).display() profile.include_path(&config.src).display()
); );
std::process::exit(1); crate::detail_exit(1);
} }
let settings = format!( let settings = format!(
@ -287,7 +287,7 @@ pub fn interactive_path() -> io::Result<Profile> {
io::stdin().read_line(&mut input)?; io::stdin().read_line(&mut input)?;
if input.is_empty() { if input.is_empty() {
eprintln!("EOF on stdin, when expecting answer to question. Giving up."); eprintln!("EOF on stdin, when expecting answer to question. Giving up.");
std::process::exit(1); crate::detail_exit(1);
} }
break match parse_with_abbrev(&input) { break match parse_with_abbrev(&input) {
Ok(profile) => profile, Ok(profile) => profile,

View file

@ -673,7 +673,7 @@ impl Step for Clippy {
} }
if !builder.config.cmd.bless() { if !builder.config.cmd.bless() {
std::process::exit(1); crate::detail_exit(1);
} }
let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run"); let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
@ -1021,7 +1021,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy`
PATH = inferred_rustfmt_dir.display(), PATH = inferred_rustfmt_dir.display(),
CHAN = builder.config.channel, CHAN = builder.config.channel,
); );
std::process::exit(1); crate::detail_exit(1);
} }
crate::format::format(&builder, !builder.config.cmd.bless(), &[]); crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
} }
@ -1251,7 +1251,7 @@ help: to test the compiler, use `--stage 1` instead
help: to test the standard library, use `--stage 0 library/std` instead help: to test the standard library, use `--stage 0 library/std` instead
note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
); );
std::process::exit(1); crate::detail_exit(1);
} }
let compiler = self.compiler; let compiler = self.compiler;

View file

@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::env; use std::env;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::{exit, Command}; use std::process::Command;
use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
use crate::channel::GitInfo; use crate::channel::GitInfo;
@ -204,7 +204,7 @@ impl Step for ToolBuild {
if !is_expected { if !is_expected {
if !is_optional_tool { if !is_optional_tool {
exit(1); crate::detail_exit(1);
} else { } else {
None None
} }

View file

@ -93,7 +93,7 @@ fn print_error(tool: &str, submodule: &str) {
eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool); eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule); eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
eprintln!("proper steps."); eprintln!("proper steps.");
std::process::exit(3); crate::detail_exit(3);
} }
fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
@ -108,7 +108,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
Ok(o) => o, Ok(o) => o,
Err(e) => { Err(e) => {
eprintln!("Failed to get changed files: {:?}", e); eprintln!("Failed to get changed files: {:?}", e);
std::process::exit(1); crate::detail_exit(1);
} }
}; };
@ -179,7 +179,7 @@ impl Step for ToolStateCheck {
} }
if did_error { if did_error {
std::process::exit(1); crate::detail_exit(1);
} }
check_changed_files(&toolstates); check_changed_files(&toolstates);
@ -225,7 +225,7 @@ impl Step for ToolStateCheck {
} }
if did_error { if did_error {
std::process::exit(1); crate::detail_exit(1);
} }
if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {

View file

@ -336,7 +336,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) {
if !try_run(cmd, print_cmd_on_fail) { if !try_run(cmd, print_cmd_on_fail) {
std::process::exit(1); crate::detail_exit(1);
} }
} }
@ -375,7 +375,7 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
pub fn run_suppressed(cmd: &mut Command) { pub fn run_suppressed(cmd: &mut Command) {
if !try_run_suppressed(cmd) { if !try_run_suppressed(cmd) {
std::process::exit(1); crate::detail_exit(1);
} }
} }
@ -465,7 +465,7 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
fn fail(s: &str) -> ! { fn fail(s: &str) -> ! {
eprintln!("\n\n{}\n\n", s); eprintln!("\n\n{}\n\n", s);
std::process::exit(1); crate::detail_exit(1);
} }
/// Copied from `std::path::absolute` until it stabilizes. /// Copied from `std::path::absolute` until it stabilizes.

View file

@ -268,6 +268,12 @@ impl clean::Generics {
} }
} }
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum Ending {
Newline,
NoNewline,
}
/// * The Generics from which to emit a where-clause. /// * The Generics from which to emit a where-clause.
/// * The number of spaces to indent each line with. /// * The number of spaces to indent each line with.
/// * Whether the where-clause needs to add a comma and newline after the last bound. /// * Whether the where-clause needs to add a comma and newline after the last bound.
@ -275,7 +281,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
gens: &'a clean::Generics, gens: &'a clean::Generics,
cx: &'a Context<'tcx>, cx: &'a Context<'tcx>,
indent: usize, indent: usize,
end_newline: bool, ending: Ending,
) -> impl fmt::Display + 'a + Captures<'tcx> { ) -> impl fmt::Display + 'a + Captures<'tcx> {
use fmt::Write; use fmt::Write;
@ -342,7 +348,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
let where_preds = comma_sep(where_predicates, false); let where_preds = comma_sep(where_predicates, false);
let clause = if f.alternate() { let clause = if f.alternate() {
if end_newline { if ending == Ending::Newline {
// add a space so stripping <br> tags and breaking spaces still renders properly // add a space so stripping <br> tags and breaking spaces still renders properly
format!(" where{where_preds}, ") format!(" where{where_preds}, ")
} else { } else {
@ -356,7 +362,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
} }
let where_preds = where_preds.to_string().replace("<br>", &br_with_padding); let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
if end_newline { if ending == Ending::Newline {
let mut clause = "&nbsp;".repeat(indent.saturating_sub(1)); let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
// add a space so stripping <br> tags and breaking spaces still renders properly // add a space so stripping <br> tags and breaking spaces still renders properly
write!( write!(
@ -1167,7 +1173,7 @@ impl clean::Impl {
fmt_type(&self.for_, f, use_absolute, cx)?; fmt_type(&self.for_, f, use_absolute, cx)?;
} }
fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, true), f)?; fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, Ending::Newline), f)?;
Ok(()) Ok(())
}) })
} }

View file

@ -70,7 +70,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::format::{ use crate::html::format::{
href, join_with_double_colon, print_abi_with_space, print_constness_with_space, href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError,
PrintWithSpace, PrintWithSpace,
}; };
use crate::html::highlight; use crate::html::highlight;
@ -747,7 +747,7 @@ fn assoc_type(
if !bounds.is_empty() { if !bounds.is_empty() {
write!(w, ": {}", print_generic_bounds(bounds, cx)) write!(w, ": {}", print_generic_bounds(bounds, cx))
} }
write!(w, "{}", print_where_clause(generics, cx, indent, false)); write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
if let Some(default) = default { if let Some(default) = default {
write!(w, " = {}", default.print(cx)) write!(w, " = {}", default.print(cx))
} }
@ -796,10 +796,10 @@ fn assoc_method(
header_len += 4; header_len += 4;
let indent_str = " "; let indent_str = " ";
render_attributes_in_pre(w, meth, indent_str); render_attributes_in_pre(w, meth, indent_str);
(4, indent_str, false) (4, indent_str, Ending::NoNewline)
} else { } else {
render_attributes_in_code(w, meth); render_attributes_in_code(w, meth);
(0, "", true) (0, "", Ending::Newline)
}; };
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len()); w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
write!( write!(

View file

@ -29,7 +29,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::format::{ use crate::html::format::{
join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause, join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
Buffer, PrintWithSpace, Buffer, Ending, PrintWithSpace,
}; };
use crate::html::highlight; use crate::html::highlight;
use crate::html::layout::Page; use crate::html::layout::Page;
@ -69,7 +69,7 @@ fn print_where_clause_and_check<'a, 'tcx: 'a>(
cx: &'a Context<'tcx>, cx: &'a Context<'tcx>,
) -> bool { ) -> bool {
let len_before = buffer.len(); let len_before = buffer.len();
write!(buffer, "{}", print_where_clause(gens, cx, 0, true)); write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline));
len_before != buffer.len() len_before != buffer.len()
} }
@ -519,7 +519,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
abi = abi, abi = abi,
name = name, name = name,
generics = f.generics.print(cx), generics = f.generics.print(cx),
where_clause = print_where_clause(&f.generics, cx, 0, true), where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
decl = f.decl.full_print(header_len, 0, header.asyncness, cx), decl = f.decl.full_print(header_len, 0, header.asyncness, cx),
notable_traits = notable_traits_decl(&f.decl, cx), notable_traits = notable_traits_decl(&f.decl, cx),
); );
@ -556,7 +556,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
); );
if !t.generics.where_predicates.is_empty() { if !t.generics.where_predicates.is_empty() {
write!(w, "{}", print_where_clause(&t.generics, cx, 0, true)); write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
} else { } else {
w.write_str(" "); w.write_str(" ");
} }
@ -1025,7 +1025,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
"trait {}{}{} = {};", "trait {}{}{} = {};",
it.name.unwrap(), it.name.unwrap(),
t.generics.print(cx), t.generics.print(cx),
print_where_clause(&t.generics, cx, 0, true), print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds(&t.bounds, true, cx) bounds(&t.bounds, true, cx)
); );
}); });
@ -1049,7 +1049,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
"type {}{}{where_clause} = impl {bounds};", "type {}{}{where_clause} = impl {bounds};",
it.name.unwrap(), it.name.unwrap(),
t.generics.print(cx), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, true), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds = bounds(&t.bounds, false, cx), bounds = bounds(&t.bounds, false, cx),
); );
}); });
@ -1074,7 +1074,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
"type {}{}{where_clause} = {type_};", "type {}{}{where_clause} = {type_};",
it.name.unwrap(), it.name.unwrap(),
t.generics.print(cx), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, true), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
type_ = t.type_.print(cx), type_ = t.type_.print(cx),
); );
}); });
@ -1784,7 +1784,7 @@ fn render_struct(
} }
w.write_str(")"); w.write_str(")");
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx, 0, false)); write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
} }
// We only want a ";" when we are displaying a tuple struct, not a variant tuple struct. // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
if structhead { if structhead {
@ -1794,7 +1794,7 @@ fn render_struct(
CtorKind::Const => { CtorKind::Const => {
// Needed for PhantomData. // Needed for PhantomData.
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx, 0, false)); write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
} }
w.write_str(";"); w.write_str(";");
} }

View file

@ -303,7 +303,7 @@ pub(crate) fn run(
// Run call-finder on all items // Run call-finder on all items
let mut calls = FxHashMap::default(); let mut calls = FxHashMap::default();
let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates }; let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
tcx.hir().deep_visit_all_item_likes(&mut finder); tcx.hir().visit_all_item_likes_in_crate(&mut finder);
// Sort call locations within a given file in document order // Sort call locations within a given file in document order
for fn_calls in calls.values_mut() { for fn_calls in calls.values_mut() {

View file

@ -0,0 +1,13 @@
// build-pass
#![feature(adt_const_params)]
#![allow(incomplete_features)]
pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
BYTES
}
pub fn main() {
assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
}

View file

@ -0,0 +1,13 @@
#![feature(adt_const_params)]
//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
#[derive(PartialEq, Eq)]
enum Nat {
Z,
S(Box<Nat>),
}
fn foo<const N: Nat>() {}
//~^ ERROR `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
fn main() {}

View file

@ -0,0 +1,18 @@
warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-80471.rs:1:12
|
LL | #![feature(adt_const_params)]
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
error[E0741]: `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
--> $DIR/issue-80471.rs:10:17
|
LL | fn foo<const N: Nat>() {}
| ^^^
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0741`.

View file

@ -16,12 +16,6 @@ error: no path from `WillChange` to `trait_def`
LL | #[rustc_then_this_would_need(trait_def)] LL | #[rustc_then_this_would_need(trait_def)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:32:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK error: OK
--> $DIR/dep-graph-struct-signature.rs:36:5 --> $DIR/dep-graph-struct-signature.rs:36:5
| |
@ -52,36 +46,12 @@ error: OK
LL | #[rustc_then_this_would_need(type_of)] LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:48:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:49:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK error: OK
--> $DIR/dep-graph-struct-signature.rs:53:5 --> $DIR/dep-graph-struct-signature.rs:53:5
| |
LL | #[rustc_then_this_would_need(type_of)] LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:55:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:56:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK error: OK
--> $DIR/dep-graph-struct-signature.rs:61:9 --> $DIR/dep-graph-struct-signature.rs:61:9
| |
@ -106,12 +76,6 @@ error: no path from `WillChange` to `type_of`
LL | #[rustc_then_this_would_need(type_of)] LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig`
--> $DIR/dep-graph-struct-signature.rs:77:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig` error: no path from `WillChange` to `fn_sig`
--> $DIR/dep-graph-struct-signature.rs:81:5 --> $DIR/dep-graph-struct-signature.rs:81:5
| |
@ -130,5 +94,41 @@ error: no path from `WillChange` to `typeck`
LL | #[rustc_then_this_would_need(typeck)] LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:32:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `WillChange` to `fn_sig`
--> $DIR/dep-graph-struct-signature.rs:77:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:48:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:49:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:55:9
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-struct-signature.rs:56:9
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 22 previous errors error: aborting due to 22 previous errors

View file

@ -28,30 +28,12 @@ error: no path from `TypeAlias` to `type_of`
LL | #[rustc_then_this_would_need(type_of)] LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:36:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: no path from `TypeAlias` to `type_of` error: no path from `TypeAlias` to `type_of`
--> $DIR/dep-graph-type-alias.rs:42:1 --> $DIR/dep-graph-type-alias.rs:42:1
| |
LL | #[rustc_then_this_would_need(type_of)] LL | #[rustc_then_this_would_need(type_of)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:44:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:45:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK error: OK
--> $DIR/dep-graph-type-alias.rs:49:1 --> $DIR/dep-graph-type-alias.rs:49:1
| |
@ -70,5 +52,23 @@ error: OK
LL | #[rustc_then_this_would_need(typeck)] LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:36:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:44:5
|
LL | #[rustc_then_this_would_need(fn_sig)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: OK
--> $DIR/dep-graph-type-alias.rs:45:5
|
LL | #[rustc_then_this_would_need(typeck)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors error: aborting due to 12 previous errors

View file

@ -1,4 +1,4 @@
pub enum Test { //~ HELP consider adding `#[derive(Default)]` to this enum pub enum Test { //~ HELP consider adding a derive
#[default] #[default]
//~^ ERROR cannot find attribute `default` in this scope //~^ ERROR cannot find attribute `default` in this scope
First, First,

View file

@ -4,11 +4,11 @@ error: cannot find attribute `default` in this scope
LL | #[default] LL | #[default]
| ^^^^^^^ | ^^^^^^^
| |
help: consider adding `#[derive(Default)]` to this enum help: consider adding a derive
--> $DIR/suggest-default-attribute.rs:1:1 |
LL + #[derive(Default)]
LL ~ pub enum Test {
| |
LL | pub enum Test {
| ^^^^^^^^^^^^^
error: aborting due to previous error error: aborting due to previous error

View file

@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/intrinsic-raw_eq-const-padding.rs:6:5 --> $DIR/intrinsic-raw_eq-const-padding.rs:6:5
| |
LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 4 bytes of memory starting at alloc3, but 1 byte is uninitialized starting at alloc3+0x1, and this operation requires initialized memory | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
error: aborting due to previous error error: aborting due to previous error

View file

@ -4,12 +4,6 @@ error: function has missing const stability attribute
LL | pub const fn foo() {} LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: associated function has missing const stability attribute
--> $DIR/missing-const-stability.rs:15:5
|
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: implementation has missing const stability attribute error: implementation has missing const stability attribute
--> $DIR/missing-const-stability.rs:27:1 --> $DIR/missing-const-stability.rs:27:1
| |
@ -19,5 +13,11 @@ LL | | fn fun() {}
LL | | } LL | | }
| |_^ | |_^
error: associated function has missing const stability attribute
--> $DIR/missing-const-stability.rs:15:5
|
LL | pub const fn foo() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors error: aborting due to 3 previous errors