Auto merge of #136116 - fmease:rollup-c8pk3mj, r=fmease

Rollup of 8 pull requests

Successful merges:

 - #126604 (Uplift `clippy::double_neg` lint as `double_negations`)
 - #135158 (Add `TooGeneric` variant to `LayoutError` and emit `Unknown`)
 - #135635 (Move `std::io::pipe` code into its own file)
 - #136072 (add two old crash tests)
 - #136079 (compiler_fence: fix example)
 - #136091 (Add some tracing to core bootstrap logic)
 - #136097 (rustc_ast: replace some len-checks + indexing with slice patterns etc.)
 - #136101 (triagebot: set myself on vacation)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-01-27 06:54:42 +00:00
commit 55459598c2
67 changed files with 974 additions and 576 deletions

View file

@ -100,7 +100,7 @@ pub struct Path {
impl PartialEq<Symbol> for Path {
#[inline]
fn eq(&self, symbol: &Symbol) -> bool {
self.segments.len() == 1 && { self.segments[0].ident.name == *symbol }
matches!(&self.segments[..], [segment] if segment.ident.name == *symbol)
}
}
@ -121,13 +121,13 @@ impl Path {
}
pub fn is_global(&self) -> bool {
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
}
/// If this path is a single identifier with no arguments, does not ensure
/// that the path resolves to a const param, the caller should check this.
pub fn is_potential_trivial_const_arg(&self) -> bool {
self.segments.len() == 1 && self.segments[0].args.is_none()
matches!(self.segments[..], [PathSegment { args: None, .. }])
}
}

View file

@ -302,7 +302,7 @@ impl AttrItem {
impl MetaItem {
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
}
pub fn name_or_empty(&self) -> Symbol {

View file

@ -1813,10 +1813,10 @@ pub fn walk_flat_map_stmt<T: MutVisitor>(
.into_iter()
.map(|kind| Stmt { id, kind, span })
.collect();
match stmts.len() {
0 => {}
1 => vis.visit_span(&mut stmts[0].span),
2.. => panic!(
match &mut stmts[..] {
[] => {}
[stmt] => vis.visit_span(&mut stmt.span),
_ => panic!(
"cloning statement `NodeId`s is prohibited by default, \
the visitor should implement custom statement visiting"
),

View file

@ -39,7 +39,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
let mut i = 0;
let mut j = lines.len();
// first line of all-stars should be omitted
if !lines.is_empty() && lines[0].chars().all(|c| c == '*') {
if lines.first().is_some_and(|line| line.chars().all(|c| c == '*')) {
i += 1;
}
@ -97,7 +97,7 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
return None;
}
}
if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
Some(lines.first()?[..i].to_string())
}
let data_s = data.as_str();

View file

@ -140,7 +140,7 @@ where
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
// should remain silent.
err_inval!(AlreadyReported(info)) => ErrorHandled::Reported(info, span),
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
err_inval!(Layout(LayoutError::TooGeneric(_))) | err_inval!(TooGeneric) => {
ErrorHandled::TooGeneric(span)
}
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {

View file

@ -201,7 +201,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
use LayoutError::*;
match layout_err {
Unknown(ty) => {
TooGeneric(ty) => {
match abi {
ExternAbi::CCmseNonSecureCall => {
// prevent double reporting of this error
@ -211,7 +211,11 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError
_ => bug!("invalid ABI: {abi}"),
}
}
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
Unknown(..)
| SizeOverflow(..)
| NormalizationFailure(..)
| ReferencesError(..)
| Cycle(..) => {
false // not our job to report these
}
}

View file

@ -122,7 +122,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("generic size {size}")
}
}
Err(LayoutError::Unknown(bad)) => {
Err(LayoutError::TooGeneric(bad)) => {
if *bad == ty {
"this type does not have a fixed size".to_owned()
} else {

View file

@ -76,6 +76,11 @@ lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$rea
lint_builtin_deref_nullptr = dereferencing a null pointer
.label = this code causes undefined behavior when executed
lint_builtin_double_negations = use of a double negation
.note = the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
.note_decrement = use `-= 1` if you meant to decrement the value
.add_parens_suggestion = add parentheses for clarity
lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
.suggestion = use `..=` for an inclusive range

View file

@ -49,16 +49,16 @@ use rustc_trait_selection::traits::{self};
use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
use crate::lints::{
BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr,
BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives,
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes,
BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed,
BuiltinTrivialBounds, BuiltinTypeAliasBounds, BuiltinUngatedAsyncFnTrackCaller,
BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub,
BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
BuiltinWhileTrue, InvalidAsmLabel,
BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasBounds,
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub,
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
};
use crate::nonstandard_style::{MethodLateContext, method_context};
use crate::{
@ -90,19 +90,11 @@ declare_lint! {
declare_lint_pass!(WhileTrue => [WHILE_TRUE]);
/// Traverse through any amount of parenthesis and return the first non-parens expression.
fn pierce_parens(mut expr: &ast::Expr) -> &ast::Expr {
while let ast::ExprKind::Paren(sub) = &expr.kind {
expr = sub;
}
expr
}
impl EarlyLintPass for WhileTrue {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if let ast::ExprKind::While(cond, _, label) = &e.kind
&& let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
&& let ast::ExprKind::Lit(token_lit) = cond.peel_parens().kind
&& let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
&& !cond.span.from_expansion()
{
@ -1576,6 +1568,58 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
}
}
declare_lint! {
/// The `double_negations` lint detects expressions of the form `--x`.
///
/// ### Example
///
/// ```rust
/// fn main() {
/// let x = 1;
/// let _b = --x;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Negating something twice is usually the same as not negating it at all.
/// However, a double negation in Rust can easily be confused with the
/// prefix decrement operator that exists in many languages derived from C.
/// Use `-(-x)` if you really wanted to negate the value twice.
///
/// To decrement a value, use `x -= 1` instead.
pub DOUBLE_NEGATIONS,
Warn,
"detects expressions of the form `--x`"
}
declare_lint_pass!(
/// Lint for expressions of the form `--x` that can be confused with C's
/// prefix decrement operator.
DoubleNegations => [DOUBLE_NEGATIONS]
);
impl EarlyLintPass for DoubleNegations {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
// only lint on the innermost `--` in a chain of `-` operators,
// even if there are 3 or more negations
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind
&& let ExprKind::Unary(UnOp::Neg, ref inner2) = inner.kind
&& !matches!(inner2.kind, ExprKind::Unary(UnOp::Neg, _))
{
cx.emit_span_lint(DOUBLE_NEGATIONS, expr.span, BuiltinDoubleNegations {
add_parens: BuiltinDoubleNegationsAddParens {
start_span: inner.span.shrink_to_lo(),
end_span: inner.span.shrink_to_hi(),
},
});
}
}
}
declare_lint_pass!(
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
@ -1594,7 +1638,8 @@ declare_lint_pass!(
UNSTABLE_FEATURES,
UNREACHABLE_PUB,
TYPE_ALIAS_BOUNDS,
TRIVIAL_BOUNDS
TRIVIAL_BOUNDS,
DOUBLE_NEGATIONS
]
);
@ -2651,7 +2696,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
}
declare_lint! {
/// The `deref_nullptr` lint detects when an null pointer is dereferenced,
/// The `deref_nullptr` lint detects when a null pointer is dereferenced,
/// which causes [undefined behavior].
///
/// ### Example

View file

@ -181,6 +181,7 @@ early_lint_methods!(
UnusedDocComment: UnusedDocComment,
Expr2024: Expr2024,
Precedence: Precedence,
DoubleNegations: DoubleNegations,
]
]
);

View file

@ -331,6 +331,24 @@ pub(crate) struct BuiltinTrivialBounds<'a> {
pub predicate: Clause<'a>,
}
#[derive(LintDiagnostic)]
#[diag(lint_builtin_double_negations)]
#[note(lint_note)]
#[note(lint_note_decrement)]
pub(crate) struct BuiltinDoubleNegations {
#[subdiagnostic]
pub add_parens: BuiltinDoubleNegationsAddParens,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(lint_add_parens_suggestion, applicability = "maybe-incorrect")]
pub(crate) struct BuiltinDoubleNegationsAddParens {
#[suggestion_part(code = "(")]
pub start_span: Span,
#[suggestion_part(code = ")")]
pub end_span: Span,
}
#[derive(LintDiagnostic)]
pub(crate) enum BuiltinEllipsisInclusiveRangePatternsLint {
#[diag(lint_builtin_ellipsis_inclusive_range_patterns)]

View file

@ -100,6 +100,8 @@ middle_strict_coherence_needs_negative_coherence =
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
.label = due to this attribute
middle_too_generic = `{$ty}` does not have a fixed size
middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
middle_unknown_layout =
@ -107,4 +109,5 @@ middle_unknown_layout =
middle_values_too_big =
values of the type `{$ty}` are too big for the target architecture
middle_written_to_path = the full type name has been written to '{$path}'

View file

@ -129,6 +129,9 @@ pub enum LayoutError<'tcx> {
#[diag(middle_unknown_layout)]
Unknown { ty: Ty<'tcx> },
#[diag(middle_too_generic)]
TooGeneric { ty: Ty<'tcx> },
#[diag(middle_values_too_big)]
Overflow { ty: Ty<'tcx> },

View file

@ -231,6 +231,7 @@ impl fmt::Display for ValidityRequirement {
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
TooGeneric(Ty<'tcx>),
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
ReferencesError(ErrorGuaranteed),
Cycle(ErrorGuaranteed),
@ -244,6 +245,7 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(_) => middle_unknown_layout,
SizeOverflow(_) => middle_values_too_big,
TooGeneric(_) => middle_too_generic,
NormalizationFailure(_, _) => middle_cannot_be_normalized,
Cycle(_) => middle_cycle,
ReferencesError(_) => middle_layout_references_error,
@ -257,6 +259,7 @@ impl<'tcx> LayoutError<'tcx> {
match self {
Unknown(ty) => E::Unknown { ty },
SizeOverflow(ty) => E::Overflow { ty },
TooGeneric(ty) => E::TooGeneric { ty },
NormalizationFailure(ty, e) => {
E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
}
@ -272,6 +275,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
LayoutError::TooGeneric(ty) => {
write!(f, "`{ty}` does not have a fixed size")
}
LayoutError::SizeOverflow(ty) => {
write!(f, "values of the type `{ty}` are too big for the target architecture")
}
@ -350,10 +356,11 @@ impl<'tcx> SizeSkeleton<'tcx> {
return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
}
}
Err(err @ LayoutError::Unknown(_)) => err,
Err(err @ LayoutError::TooGeneric(_)) => err,
// We can't extract SizeSkeleton info from other layout errors
Err(
e @ LayoutError::Cycle(_)
| e @ LayoutError::Unknown(_)
| e @ LayoutError::SizeOverflow(_)
| e @ LayoutError::NormalizationFailure(..)
| e @ LayoutError::ReferencesError(_),
@ -413,10 +420,9 @@ impl<'tcx> SizeSkeleton<'tcx> {
// Alignment is unchanged by arrays.
return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
}
Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
Err(err)
}
SizeSkeleton::Pointer { .. } => Err(err),
SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
}
}

View file

@ -197,6 +197,7 @@ pub(crate) mod rustc {
match err {
LayoutError::Unknown(..)
| LayoutError::ReferencesError(..)
| LayoutError::TooGeneric(..)
| LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
LayoutError::Cycle(err) => Self::TypeError(*err),

View file

@ -104,14 +104,12 @@ fn map_error<'tcx>(
// This is sometimes not a compile error if there are trivially false where clauses.
// See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
if !field.ty.is_sized(cx.tcx(), cx.typing_env) {
let guar = cx.tcx().dcx().delayed_bug(format!(
if cx.typing_env.param_env.caller_bounds().is_empty() {
cx.tcx().dcx().delayed_bug(format!(
"encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
));
LayoutError::ReferencesError(guar)
} else {
LayoutError::Unknown(ty)
}
LayoutError::Unknown(ty)
}
LayoutCalculatorError::EmptyUnion => {
// This is always a compile error.
@ -146,6 +144,35 @@ fn univariant_uninterned<'tcx>(
cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err))
}
fn validate_const_with_value<'tcx>(
const_: ty::Const<'tcx>,
ty: Ty<'tcx>,
cx: &LayoutCx<'tcx>,
) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> {
match const_.kind() {
ty::ConstKind::Value(..) => Ok(const_),
ty::ConstKind::Error(guar) => {
return Err(error(cx, LayoutError::ReferencesError(guar)));
}
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
if !const_.has_param() {
bug!("no generic type found in the type: {ty:?}");
}
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
ty::ConstKind::Unevaluated(_) => {
if !const_.has_param() {
return Err(error(cx, LayoutError::Unknown(ty)));
} else {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
}
ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
bug!("unexpected type: {ty:?}");
}
}
}
fn layout_of_uncached<'tcx>(
cx: &LayoutCx<'tcx>,
ty: Ty<'tcx>,
@ -182,12 +209,13 @@ fn layout_of_uncached<'tcx>(
&mut layout.backend_repr
{
if let Some(start) = start {
scalar.valid_range_mut().start = start
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
scalar.valid_range_mut().start =
validate_const_with_value(start, ty, cx)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
}
if let Some(end) = end {
let mut end = end
let mut end = validate_const_with_value(end, ty, cx)?
.try_to_bits(tcx, cx.typing_env)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
if !include_end {
@ -319,17 +347,13 @@ fn layout_of_uncached<'tcx>(
}
// Arrays and slices.
ty::Array(element, mut count) => {
if count.has_aliases() {
count = tcx.normalize_erasing_regions(cx.typing_env, count);
if count.has_aliases() {
return Err(error(cx, LayoutError::Unknown(ty)));
}
}
let count = count
ty::Array(element, count) => {
let count = validate_const_with_value(count, ty, cx)?
.to_valtree()
.0
.try_to_target_usize(tcx)
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
let element = cx.layout_of(element)?;
let size = element
.size
@ -687,6 +711,9 @@ fn layout_of_uncached<'tcx>(
// Types with no meaningful known layout.
ty::Alias(..) => {
if ty.has_param() {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
// NOTE(eddyb) `layout_of` query should've normalized these away,
// if that was possible, so there's no reason to try again here.
return Err(error(cx, LayoutError::Unknown(ty)));
@ -696,7 +723,11 @@ fn layout_of_uncached<'tcx>(
bug!("Layout::compute: unexpected type `{}`", ty)
}
ty::Placeholder(..) | ty::Param(_) => {
ty::Param(_) => {
return Err(error(cx, LayoutError::TooGeneric(ty)));
}
ty::Placeholder(..) => {
return Err(error(cx, LayoutError::Unknown(ty)));
}
})

View file

@ -3727,33 +3727,33 @@ pub fn fence(order: Ordering) {
///
/// # Examples
///
/// Without `compiler_fence`, the `assert_eq!` in following code
/// is *not* guaranteed to succeed, despite everything happening in a single thread.
/// To see why, remember that the compiler is free to swap the stores to
/// `IMPORTANT_VARIABLE` and `IS_READY` since they are both
/// `Ordering::Relaxed`. If it does, and the signal handler is invoked right
/// after `IS_READY` is updated, then the signal handler will see
/// `IS_READY=1`, but `IMPORTANT_VARIABLE=0`.
/// Using a `compiler_fence` remedies this situation.
/// Without the two `compiler_fence` calls, the read of `IMPORTANT_VARIABLE` in `signal_handler`
/// is *undefined behavior* due to a data race, despite everything happening in a single thread.
/// This is because the signal handler is considered to run concurrently with its associated
/// thread, and explicit synchronization is required to pass data between a thread and its
/// signal handler. The code below uses two `compiler_fence` calls to establish the usual
/// release-acquire synchronization pattern (see [`fence`] for an image).
///
/// ```
/// use std::sync::atomic::{AtomicBool, AtomicUsize};
/// use std::sync::atomic::AtomicBool;
/// use std::sync::atomic::Ordering;
/// use std::sync::atomic::compiler_fence;
///
/// static IMPORTANT_VARIABLE: AtomicUsize = AtomicUsize::new(0);
/// static mut IMPORTANT_VARIABLE: usize = 0;
/// static IS_READY: AtomicBool = AtomicBool::new(false);
///
/// fn main() {
/// IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
/// // prevent earlier writes from being moved beyond this point
/// unsafe { IMPORTANT_VARIABLE = 42 };
/// // Marks earlier writes as being released with future relaxed stores.
/// compiler_fence(Ordering::Release);
/// IS_READY.store(true, Ordering::Relaxed);
/// }
///
/// fn signal_handler() {
/// if IS_READY.load(Ordering::Relaxed) {
/// assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
/// // Acquires writes that were released with relaxed stores that we read from.
/// compiler_fence(Ordering::Acquire);
/// assert_eq!(unsafe { IMPORTANT_VARIABLE }, 42);
/// }
/// }
/// ```

View file

@ -310,6 +310,8 @@ pub use self::error::RawOsError;
pub use self::error::SimpleMessage;
#[unstable(feature = "io_const_error", issue = "133448")]
pub use self::error::const_error;
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub use self::pipe::{PipeReader, PipeWriter, pipe};
#[stable(feature = "is_terminal", since = "1.70.0")]
pub use self::stdio::IsTerminal;
pub(crate) use self::stdio::attempt_print_to_stderr;
@ -330,7 +332,6 @@ pub use self::{
};
use crate::mem::take;
use crate::ops::{Deref, DerefMut};
use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
use crate::{cmp, fmt, slice, str, sys};
mod buffered;
@ -338,6 +339,7 @@ pub(crate) mod copy;
mod cursor;
mod error;
mod impls;
mod pipe;
pub mod prelude;
mod stdio;
mod util;
@ -3251,257 +3253,3 @@ impl<B: BufRead> Iterator for Lines<B> {
}
}
}
/// Create an anonymous pipe that is close-on-exec and blocking.
///
/// # Behavior
///
/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
/// typically used to communicate between two or more separate processes, as there are better,
/// faster ways to communicate within a single process.
///
/// In particular:
///
/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
/// * A write on a [`PipeWriter`] blocks when the pipe is full.
/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
/// returns EOF.
/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
/// writes (above a target-specific threshold) may have their data interleaved.
/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
/// given byte will only get consumed by one reader. There are no guarantees about data
/// interleaving.
/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
///
/// # Capacity
///
/// Pipe capacity is platform dependent. To quote the Linux [man page]:
///
/// > Different implementations have different limits for the pipe capacity. Applications should
/// > not rely on a particular capacity: an application should be designed so that a reading process
/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// # use std::process::Command;
/// # use std::io::{Read, Write};
/// let (ping_rx, mut ping_tx) = std::io::pipe()?;
/// let (mut pong_rx, pong_tx) = std::io::pipe()?;
///
/// // Spawn a process that echoes its input.
/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
///
/// ping_tx.write_all(b"hello")?;
/// // Close to unblock echo_server's reader.
/// drop(ping_tx);
///
/// let mut buf = String::new();
/// // Block until echo_server's writer is closed.
/// pong_rx.read_to_string(&mut buf)?;
/// assert_eq!(&buf, "hello");
///
/// echo_server.wait()?;
/// # Ok(())
/// # }
/// ```
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[inline]
pub fn pipe() -> Result<(PipeReader, PipeWriter)> {
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
}
/// Read end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeReader(pub(crate) AnonPipe);
/// Write end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeWriter(pub(crate) AnonPipe);
impl PipeReader {
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// # use std::fs;
/// # use std::io::Write;
/// # use std::process::Command;
/// const NUM_SLOT: u8 = 2;
/// const NUM_PROC: u8 = 5;
/// const OUTPUT: &str = "work.txt";
///
/// let mut jobs = vec![];
/// let (reader, mut writer) = std::io::pipe()?;
///
/// // Write NUM_SLOT characters the pipe.
/// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
///
/// // Spawn several processes that read a character from the pipe, do some work, then
/// // write back to the pipe. When the pipe is empty, the processes block, so only
/// // NUM_SLOT processes can be working at any given time.
/// for _ in 0..NUM_PROC {
/// jobs.push(
/// Command::new("bash")
/// .args(["-c",
/// &format!(
/// "read -n 1\n\
/// echo -n 'x' >> '{OUTPUT}'\n\
/// echo -n '|'",
/// ),
/// ])
/// .stdin(reader.try_clone()?)
/// .stdout(writer.try_clone()?)
/// .spawn()?,
/// );
/// }
///
/// // Wait for all jobs to finish.
/// for mut job in jobs {
/// job.wait()?;
/// }
///
/// // Check our work and clean up.
/// let xs = fs::read_to_string(OUTPUT)?;
/// fs::remove_file(OUTPUT)?;
/// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> Result<Self> {
self.0.try_clone().map(Self)
}
}
impl PipeWriter {
/// Create a new [`PipeWriter`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// # use std::process::Command;
/// # use std::io::Read;
/// let (mut reader, writer) = std::io::pipe()?;
///
/// // Spawn a process that writes to stdout and stderr.
/// let mut peer = Command::new("bash")
/// .args([
/// "-c",
/// "echo -n foo\n\
/// echo -n bar >&2"
/// ])
/// .stdout(writer.try_clone()?)
/// .stderr(writer)
/// .spawn()?;
///
/// // Read and check the result.
/// let mut msg = String::new();
/// reader.read_to_string(&mut msg)?;
/// assert_eq!(&msg, "foobar");
///
/// peer.wait()?;
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> Result<Self> {
self.0.try_clone().map(Self)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
self.0.read_buf(buf)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
self.0.read_buf(buf)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}

260
library/std/src/io/pipe.rs Normal file
View file

@ -0,0 +1,260 @@
use crate::io;
use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
/// Create an anonymous pipe.
///
/// # Behavior
///
/// A pipe is a one-way data channel provided by the OS, which works across processes. A pipe is
/// typically used to communicate between two or more separate processes, as there are better,
/// faster ways to communicate within a single process.
///
/// In particular:
///
/// * A read on a [`PipeReader`] blocks until the pipe is non-empty.
/// * A write on a [`PipeWriter`] blocks when the pipe is full.
/// * When all copies of a [`PipeWriter`] are closed, a read on the corresponding [`PipeReader`]
/// returns EOF.
/// * [`PipeWriter`] can be shared, and multiple processes or threads can write to it at once, but
/// writes (above a target-specific threshold) may have their data interleaved.
/// * [`PipeReader`] can be shared, and multiple processes or threads can read it at once. Any
/// given byte will only get consumed by one reader. There are no guarantees about data
/// interleaving.
/// * Portable applications cannot assume any atomicity of messages larger than a single byte.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `pipe` function on Unix and the
/// `CreatePipe` function on Windows.
///
/// Note that this [may change in the future][changes].
///
/// # Capacity
///
/// Pipe capacity is platform dependent. To quote the Linux [man page]:
///
/// > Different implementations have different limits for the pipe capacity. Applications should
/// > not rely on a particular capacity: an application should be designed so that a reading process
/// > consumes data as soon as it is available, so that a writing process does not remain blocked.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::process::Command;
/// use std::io::{pipe, Read, Write};
/// let (ping_rx, mut ping_tx) = pipe()?;
/// let (mut pong_rx, pong_tx) = pipe()?;
///
/// // Spawn a process that echoes its input.
/// let mut echo_server = Command::new("cat").stdin(ping_rx).stdout(pong_tx).spawn()?;
///
/// ping_tx.write_all(b"hello")?;
/// // Close to unblock echo_server's reader.
/// drop(ping_tx);
///
/// let mut buf = String::new();
/// // Block until echo_server's writer is closed.
/// pong_rx.read_to_string(&mut buf)?;
/// assert_eq!(&buf, "hello");
///
/// echo_server.wait()?;
/// # Ok(())
/// # }
/// ```
/// [changes]: io#platform-specific-behavior
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[inline]
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
}
/// Read end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeReader(pub(crate) AnonPipe);
/// Write end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[derive(Debug)]
pub struct PipeWriter(pub(crate) AnonPipe);
impl PipeReader {
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::fs;
/// use std::io::{pipe, Write};
/// use std::process::Command;
/// const NUM_SLOT: u8 = 2;
/// const NUM_PROC: u8 = 5;
/// const OUTPUT: &str = "work.txt";
///
/// let mut jobs = vec![];
/// let (reader, mut writer) = pipe()?;
///
/// // Write NUM_SLOT characters the pipe.
/// writer.write_all(&[b'|'; NUM_SLOT as usize])?;
///
/// // Spawn several processes that read a character from the pipe, do some work, then
/// // write back to the pipe. When the pipe is empty, the processes block, so only
/// // NUM_SLOT processes can be working at any given time.
/// for _ in 0..NUM_PROC {
/// jobs.push(
/// Command::new("bash")
/// .args(["-c",
/// &format!(
/// "read -n 1\n\
/// echo -n 'x' >> '{OUTPUT}'\n\
/// echo -n '|'",
/// ),
/// ])
/// .stdin(reader.try_clone()?)
/// .stdout(writer.try_clone()?)
/// .spawn()?,
/// );
/// }
///
/// // Wait for all jobs to finish.
/// for mut job in jobs {
/// job.wait()?;
/// }
///
/// // Check our work and clean up.
/// let xs = fs::read_to_string(OUTPUT)?;
/// fs::remove_file(OUTPUT)?;
/// assert_eq!(xs, "x".repeat(NUM_PROC.into()));
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
impl PipeWriter {
/// Create a new [`PipeWriter`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
/// use std::process::Command;
/// use std::io::{pipe, Read};
/// let (mut reader, writer) = pipe()?;
///
/// // Spawn a process that writes to stdout and stderr.
/// let mut peer = Command::new("bash")
/// .args([
/// "-c",
/// "echo -n foo\n\
/// echo -n bar >&2"
/// ])
/// .stdout(writer.try_clone()?)
/// .stderr(writer)
/// .spawn()?;
///
/// // Read and check the result.
/// let mut msg = String::new();
/// reader.read_to_string(&mut msg)?;
/// assert_eq!(&msg, "foobar");
///
/// peer.wait()?;
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
#[inline]
fn is_read_vectored(&self) -> bool {
self.0.is_read_vectored()
}
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.0.read_to_end(buf)
}
fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> {
self.0.read_buf(buf)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl io::Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
#[inline]
fn is_write_vectored(&self) -> bool {
self.0.is_write_vectored()
}
}

View file

@ -0,0 +1,18 @@
use crate::io::{Read, Write, pipe};
#[test]
#[cfg(all(windows, unix, not(miri)))]
fn pipe_creation_clone_and_rw() {
let (rx, tx) = pipe().unwrap();
tx.try_clone().unwrap().write_all(b"12345").unwrap();
drop(tx);
let mut rx2 = rx.try_clone().unwrap();
drop(rx);
let mut s = String::new();
rx2.read_to_string(&mut s).unwrap();
drop(rx2);
assert_eq!(s, "12345");
}

View file

@ -821,20 +821,3 @@ fn try_oom_error() {
let io_err = io::Error::from(reserve_err);
assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind());
}
#[test]
#[cfg(all(windows, unix, not(miri)))]
fn pipe_creation_clone_and_rw() {
let (rx, tx) = std::io::pipe().unwrap();
tx.try_clone().unwrap().write_all(b"12345").unwrap();
drop(tx);
let mut rx2 = rx.try_clone().unwrap();
drop(rx);
let mut s = String::new();
rx2.read_to_string(&mut s).unwrap();
drop(rx2);
assert_eq!(s, "12345");
}

View file

@ -16,11 +16,7 @@ use bootstrap::{
};
use build_helper::ci::CiEnv;
#[cfg(feature = "tracing")]
use tracing::*;
#[cfg(feature = "tracing")]
use tracing_subscriber::EnvFilter;
#[cfg(feature = "tracing")]
use tracing_subscriber::prelude::*;
use tracing::{debug, instrument};
#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "main"))]
fn main() {
@ -33,7 +29,11 @@ fn main() {
return;
}
#[cfg(feature = "tracing")]
debug!("parsing flags");
let flags = Flags::parse(&args);
#[cfg(feature = "tracing")]
debug!("parsing config based on flags");
let config = Config::parse(flags);
let mut build_lock;
@ -95,6 +95,8 @@ fn main() {
let dump_bootstrap_shims = config.dump_bootstrap_shims;
let out_dir = config.out.clone();
#[cfg(feature = "tracing")]
debug!("creating new build based on config");
Build::new(config).build();
if suggest_setup {
@ -211,16 +213,14 @@ fn check_version(config: &Config) -> Option<String> {
// "tracing", instrument(..))]`.
#[cfg(feature = "tracing")]
fn setup_tracing() {
let filter = EnvFilter::from_env("BOOTSTRAP_TRACING");
let layer = tracing_tree::HierarchicalLayer::default()
.with_writer(std::io::stderr)
.with_ansi(true)
.with_targets(true)
.with_bracketed_fields(true)
.with_indent_amount(2)
.with_indent_lines(true);
let subscriber = tracing_subscriber::registry().with(filter).with(layer);
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
tracing::subscriber::set_global_default(subscriber).unwrap();
trace!("tracing subscriber setup");
let filter = EnvFilter::from_env("BOOTSTRAP_TRACING");
// cf. <https://docs.rs/tracing-tree/latest/tracing_tree/struct.HierarchicalLayer.html>.
let layer = tracing_tree::HierarchicalLayer::default().with_targets(true).with_indent_amount(2);
let registry = tracing_subscriber::registry().with(filter).with(layer);
tracing::subscriber::set_global_default(registry).unwrap();
}

View file

@ -18,6 +18,8 @@ use build_helper::exit;
use build_helper::git::{GitConfig, get_closest_merge_commit, output_result};
use serde::{Deserialize, Deserializer};
use serde_derive::Deserialize;
#[cfg(feature = "tracing")]
use tracing::{instrument, span};
use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
use crate::core::build_steps::llvm;
@ -1227,7 +1229,14 @@ define_config! {
}
impl Config {
#[cfg_attr(
feature = "tracing",
instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::default_opts")
)]
pub fn default_opts() -> Config {
#[cfg(feature = "tracing")]
span!(target: "CONFIG_HANDLING", tracing::Level::TRACE, "constructing default config");
Config {
bypass_bootstrap_lock: false,
llvm_optimize: true,
@ -1311,10 +1320,23 @@ impl Config {
})
}
#[cfg_attr(
feature = "tracing",
instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all)
)]
pub fn parse(flags: Flags) -> Config {
Self::parse_inner(flags, Self::get_toml)
}
#[cfg_attr(
feature = "tracing",
instrument(
target = "CONFIG_HANDLING",
level = "trace",
name = "Config::parse_inner",
skip_all
)
)]
pub(crate) fn parse_inner(
mut flags: Flags,
get_toml: impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>,
@ -1323,6 +1345,17 @@ impl Config {
// Set flags.
config.paths = std::mem::take(&mut flags.paths);
#[cfg(feature = "tracing")]
span!(
target: "CONFIG_HANDLING",
tracing::Level::TRACE,
"collecting paths and path exclusions",
"flags.paths" = ?flags.paths,
"flags.skip" = ?flags.skip,
"flags.exclude" = ?flags.exclude
);
config.skip = flags
.skip
.into_iter()
@ -1339,6 +1372,14 @@ impl Config {
})
.collect();
#[cfg(feature = "tracing")]
span!(
target: "CONFIG_HANDLING",
tracing::Level::TRACE,
"normalizing and combining `flag.skip`/`flag.exclude` paths",
"config.skip" = ?config.skip,
);
config.include_default_paths = flags.include_default_paths;
config.rustc_error_format = flags.rustc_error_format;
config.json_output = flags.json_output;
@ -1418,7 +1459,11 @@ impl Config {
config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file();
// Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
// Find configuration file, with the following cascading fallback (first match wins):
// - `--config <path>`
// - `RUST_BOOTSTRAP_CONFIG`
// - `./config.toml`
// - `config.toml` in the root directory.
let toml_path = flags
.config
.clone()

View file

@ -6,6 +6,8 @@
use std::path::{Path, PathBuf};
use clap::{CommandFactory, Parser, ValueEnum};
#[cfg(feature = "tracing")]
use tracing::instrument;
use crate::core::build_steps::setup::Profile;
use crate::core::builder::{Builder, Kind};
@ -211,6 +213,10 @@ impl Flags {
}
}
#[cfg_attr(
feature = "tracing",
instrument(level = "trace", name = "Flags::parse", skip_all, fields(args = ?args))
)]
pub fn parse(args: &[String]) -> Self {
Flags::parse_from(normalize_args(args))
}

View file

@ -28,6 +28,8 @@ use std::{env, fs, io, str};
use build_helper::ci::gha;
use build_helper::exit;
use termcolor::{ColorChoice, StandardStream, WriteColor};
#[cfg(feature = "tracing")]
use tracing::{debug, instrument, span, trace};
use utils::build_stamp::BuildStamp;
use utils::channel::GitInfo;
@ -537,14 +539,25 @@ impl Build {
}
/// Executes the entire build, as configured by the flags and configuration.
#[cfg_attr(feature = "tracing", instrument(level = "debug", name = "Build::build", skip_all))]
pub fn build(&mut self) {
#[cfg(feature = "tracing")]
trace!("setting up job management");
unsafe {
crate::utils::job::setup(self);
}
#[cfg(feature = "tracing")]
trace!("downloading rustfmt early");
// Download rustfmt early so that it can be used in rust-analyzer configs.
let _ = &builder::Builder::new(self).initial_rustfmt();
#[cfg(feature = "tracing")]
let hardcoded_span =
span!(tracing::Level::DEBUG, "handling hardcoded subcommands (Format, Suggest, Perf)")
.entered();
// hardcoded subcommands
match &self.config.cmd {
Subcommand::Format { check, all } => {
@ -561,25 +574,50 @@ impl Build {
Subcommand::Perf { .. } => {
return core::build_steps::perf::perf(&builder::Builder::new(self));
}
_ => (),
_cmd => {
#[cfg(feature = "tracing")]
debug!(cmd = ?_cmd, "not a hardcoded subcommand; returning to normal handling");
}
}
#[cfg(feature = "tracing")]
drop(hardcoded_span);
#[cfg(feature = "tracing")]
debug!("handling subcommand normally");
if !self.config.dry_run() {
#[cfg(feature = "tracing")]
let _real_run_span = span!(tracing::Level::DEBUG, "executing real run").entered();
{
#[cfg(feature = "tracing")]
let _sanity_check_span =
span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered();
// We first do a dry-run. This is a sanity-check to ensure that
// steps don't do anything expensive in the dry-run.
self.config.dry_run = DryRun::SelfCheck;
let builder = builder::Builder::new(self);
builder.execute_cli();
}
#[cfg(feature = "tracing")]
let _actual_run_span =
span!(tracing::Level::DEBUG, "(2) executing actual run").entered();
self.config.dry_run = DryRun::Disabled;
let builder = builder::Builder::new(self);
builder.execute_cli();
} else {
#[cfg(feature = "tracing")]
let _dry_run_span = span!(tracing::Level::DEBUG, "executing dry run").entered();
let builder = builder::Builder::new(self);
builder.execute_cli();
}
#[cfg(feature = "tracing")]
debug!("checking for postponed test failures from `test --no-fail-fast`");
// Check for postponed failures from `test --no-fail-fast`.
let failures = self.delayed_failures.borrow();
if failures.len() > 0 {

View file

@ -1,6 +1,6 @@
# Debugging bootstrap
> FIXME: this page could be expanded
> FIXME: this section should be expanded
## `tracing` in bootstrap
@ -10,21 +10,69 @@ Bootstrap has conditional [`tracing`][tracing] setup to provide structured loggi
### Enabling `tracing` output
Bootstrap will conditionally enable `tracing` output if the `BOOTSTRAP_TRACING` env var is set.
Bootstrap will conditionally build `tracing` support and enable `tracing` output if the `BOOTSTRAP_TRACING` env var is set.
Example usage:
#### Basic usage
Example basic usage[^just-trace]:
[^just-trace]: It is not recommend to use *just* `BOOTSTRAP_TRACING=TRACE` because that will dump *everything* at `TRACE` level, including logs intentionally gated behind custom targets as they are too verbose even for `TRACE` level by default.
```bash
$ BOOTSTRAP_TRACING=TRACE ./x build library --stage 1
$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x build library --stage 1
```
Example output[^experimental]:
Example output[^unstable]:
![Example bootstrap tracing output](./debugging-bootstrap/tracing-output-example.png)
```
$ BOOTSTRAP_TRACING=bootstrap=TRACE ./x check src/bootstrap/
Building bootstrap
Compiling bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
Finished `dev` profile [unoptimized] target(s) in 2.74s
DEBUG bootstrap parsing flags
bootstrap::core::config::flags::Flags::parse args=["check", "src/bootstrap/"]
DEBUG bootstrap parsing config based on flags
DEBUG bootstrap creating new build based on config
bootstrap::Build::build
TRACE bootstrap setting up job management
TRACE bootstrap downloading rustfmt early
bootstrap::handling hardcoded subcommands (Format, Suggest, Perf)
DEBUG bootstrap not a hardcoded subcommand; returning to normal handling, cmd=Check { all_targets: false }
DEBUG bootstrap handling subcommand normally
bootstrap::executing real run
bootstrap::(1) executing dry-run sanity-check
bootstrap::(2) executing actual run
Checking stage0 library artifacts (x86_64-unknown-linux-gnu)
Finished `release` profile [optimized + debuginfo] target(s) in 0.04s
Checking stage0 compiler artifacts {rustc-main, rustc_abi, rustc_arena, rustc_ast, rustc_ast_ir, rustc_ast_lowering, rustc_ast_passes, rustc_ast_pretty, rustc_attr_data_structures, rustc_attr_parsing, rustc_baked_icu_data, rustc_borrowck, rustc_builtin_macros, rustc_codegen_llvm, rustc_codegen_ssa, rustc_const_eval, rustc_data_structures, rustc_driver, rustc_driver_impl, rustc_error_codes, rustc_error_messages, rustc_errors, rustc_expand, rustc_feature, rustc_fluent_macro, rustc_fs_util, rustc_graphviz, rustc_hir, rustc_hir_analysis, rustc_hir_pretty, rustc_hir_typeck, rustc_incremental, rustc_index, rustc_index_macros, rustc_infer, rustc_interface, rustc_lexer, rustc_lint, rustc_lint_defs, rustc_llvm, rustc_log, rustc_macros, rustc_metadata, rustc_middle, rustc_mir_build, rustc_mir_dataflow, rustc_mir_transform, rustc_monomorphize, rustc_next_trait_solver, rustc_parse, rustc_parse_format, rustc_passes, rustc_pattern_analysis, rustc_privacy, rustc_query_impl, rustc_query_system, rustc_resolve, rustc_sanitizers, rustc_serialize, rustc_session, rustc_smir, rustc_span, rustc_symbol_mangling, rustc_target, rustc_trait_selection, rustc_traits, rustc_transmute, rustc_ty_utils, rustc_type_ir, rustc_type_ir_macros, stable_mir} (x86_64-unknown-linux-gnu)
Finished `release` profile [optimized + debuginfo] target(s) in 0.23s
Checking stage0 bootstrap artifacts (x86_64-unknown-linux-gnu)
Checking bootstrap v0.0.0 (/home/joe/repos/rust/src/bootstrap)
Finished `release` profile [optimized + debuginfo] target(s) in 0.64s
DEBUG bootstrap checking for postponed test failures from `test --no-fail-fast`
Build completed successfully in 0:00:08
```
[^experimental]: This shows what's *possible* with the infra in an experimental implementation.
#### Controlling log output
The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter]. The `TRACE` filter will enable *all* `trace` level or less verbose level tracing output.
The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter].
There are two orthogonal ways to control which kind of logs you want:
1. You can specify the log **level**, e.g. `DEBUG` or `TRACE`.
2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` vs custom targets like `CONFIG_HANDLING`.
- Custom targets are used to limit what is output when `BOOTSTRAP_TRACING=bootstrap=TRACE` is used, as they can be too verbose even for `TRACE` level by default. Currently used custom targets:
- `CONFIG_HANDLING`
The `TRACE` filter will enable *all* `trace` level or less verbose level tracing output.
You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally):
```bash
$ BOOTSTRAP_TRACING=CONFIG_HANDLING=TRACE ./x build library --stage 1
```
[^unstable]: This output is always subject to further changes.
[tracing-env-filter]: https://docs.rs/tracing-subscriber/0.3.19/tracing_subscriber/filter/struct.EnvFilter.html
@ -73,28 +121,6 @@ For `#[instrument]`, it's recommended to:
- Explicitly pick an instrumentation name via `name = ".."` to distinguish between e.g. `run` of different steps.
- Take care to not cause diverging behavior via tracing, e.g. building extra things only when tracing infra is enabled.
### Enabling `tracing` bootstrap feature in rust-analyzer
### rust-analyzer integration?
You can adjust your `settings.json`'s `rust-analyzer.check.overrideCommand` and `rust-analyzer.cargo.buildScripts.overrideCommand` if you want to also enable `logging` cargo feature by default in your editor. This is mostly useful if you want proper r-a completions and such when working on bootstrap itself.
```json
"rust-analyzer.check.overrideCommand": [
"BOOTSTRAP_TRACING=1", // <- BOOTSTRAP_TRACING=1 won't enable tracing filter, but it will activate bootstrap's `tracing` feature
"python3",
"x.py",
"check",
"--json-output",
"--build-dir=build-rust-analyzer"
],
```
```json
"rust-analyzer.cargo.buildScripts.overrideCommand": [
"BOOTSTRAP_TRACING=1", // <- note this
"python3",
"x.py",
"check",
"--json-output",
"--build-dir=build-rust-analyzer"
],
```
Unfortunately, because bootstrap is a `rust-analyzer.linkedProjects`, you can't ask r-a to check/build bootstrap itself with `tracing` feature enabled to get relevant completions, due to lack of support as described in <https://github.com/rust-lang/rust-analyzer/issues/8521>.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

View file

@ -28,13 +28,11 @@
{% endfor %}
</ul>
{% endif %}
{# This kind of layout error can occur with valid code, e.g. if you try to
get the layout of a generic type such as `Vec<T>`. #}
{# This kind of layout error can occur with valid code, for example
if there are trivial bounds: `struct Foo(str, str) where str: Sized;`. #}
{% when Err(LayoutError::Unknown(_)) %}
<p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #}
<strong>Note:</strong> Unable to compute type layout. {# #}
</p>
{# This kind of error probably can't happen with valid code, but we don't
want to panic and prevent the docs from building, so we just let the
@ -44,6 +42,14 @@
<strong>Note:</strong> Encountered an error during type layout; {#+ #}
the type was too big. {# #}
</p>
{# This kind of layout error can occur with valid code, e.g. if you try to
get the layout of a generic type such as `Vec<T>`. #}
{% when Err(LayoutError::TooGeneric(_)) %}
<p> {# #}
<strong>Note:</strong> Unable to compute type layout, {#+ #}
possibly due to this type having generic parameters. {#+ #}
Layout can only be computed for concrete, fully-instantiated types. {# #}
</p>
{% when Err(LayoutError::ReferencesError(_)) %}
<p> {# #}
<strong>Note:</strong> Encountered an error during type layout; {#+ #}

View file

@ -47,9 +47,9 @@ unset CARGO_MANIFEST_DIR
# Run a lint and make sure it produces the expected output. It's also expected to exit with code 1
# FIXME: How to match the clippy invocation in compile-test.rs?
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/double_neg.rs 2>double_neg.stderr && exit 1
sed -e "/= help: for/d" double_neg.stderr > normalized.stderr
diff -u normalized.stderr tests/ui/double_neg.stderr
./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/box_default.rs 2>box_default.stderr && exit 1
sed -e "/= help: for/d" box_default.stderr > normalized.stderr
diff -u normalized.stderr tests/ui/box_default.stderr
# make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same
SYSROOT=$(rustc --print sysroot)

View file

@ -33,7 +33,7 @@ You can configure lint levels on the command line by adding
`-A/W/D clippy::lint_name` like this:
```bash
cargo clippy -- -Aclippy::style -Wclippy::double_neg -Dclippy::perf
cargo clippy -- -Aclippy::style -Wclippy::box_default -Dclippy::perf
```
For [CI] all warnings can be elevated to errors which will in turn fail
@ -101,11 +101,10 @@ You can configure lint levels in source code the same way you can configure
```rust,ignore
#![allow(clippy::style)]
#[warn(clippy::double_neg)]
#[warn(clippy::box_default)]
fn main() {
let x = 1;
let y = --x;
// ^^ warning: double negation
let _ = Box::<String>::new(Default::default());
// ^ warning: `Box::new(_)` of default value
}
```

View file

@ -455,7 +455,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
});
// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token == TokenKind::Ident) {
while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
let mut iter = iter
.by_ref()
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
@ -465,7 +465,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
// matches `!{`
match_tokens!(iter, Bang OpenBrace);
if let Some(LintDeclSearchResult { range, .. }) =
iter.find(|result| result.token == TokenKind::CloseBrace)
iter.find(|result| result.token_kind == TokenKind::CloseBrace)
{
last_decl_curly_offset = Some(range.end);
}

View file

@ -507,7 +507,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::misc::USED_UNDERSCORE_BINDING_INFO,
crate::misc::USED_UNDERSCORE_ITEMS_INFO,
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
crate::misc_early::DOUBLE_NEG_INFO,
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,

View file

@ -129,6 +129,8 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
("clippy::clone_double_ref", "suspicious_double_ref_op"),
#[clippy::version = ""]
("clippy::cmp_nan", "invalid_nan_comparisons"),
#[clippy::version = "1.86.0"]
("clippy::double_neg", "double_negations"),
#[clippy::version = ""]
("clippy::drop_bounds", "drop_bounds"),
#[clippy::version = ""]

View file

@ -1,18 +0,0 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext;
use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
cx,
DOUBLE_NEG,
expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
);
}
}
}

View file

@ -1,5 +1,4 @@
mod builtin_type_shadow;
mod double_neg;
mod literal_suffix;
mod mixed_case_hex_literals;
mod redundant_at_rest_pattern;
@ -85,25 +84,6 @@ declare_clippy_lint! {
"function arguments having names which only differ by an underscore"
}
declare_clippy_lint! {
/// ### What it does
/// Detects expressions of the form `--x`.
///
/// ### Why is this bad?
/// It can mislead C/C++ programmers to think `x` was
/// decremented.
///
/// ### Example
/// ```no_run
/// let mut x = 3;
/// --x;
/// ```
#[clippy::version = "pre 1.29.0"]
pub DOUBLE_NEG,
style,
"`--x`, which is a double negation of `x` and not a pre-decrement as in C/C++"
}
declare_clippy_lint! {
/// ### What it does
/// Warns on hexadecimal literals with mixed-case letter
@ -352,7 +332,6 @@ declare_clippy_lint! {
declare_lint_pass!(MiscEarlyLints => [
UNNEEDED_FIELD_PATTERN,
DUPLICATE_UNDERSCORE_ARGUMENT,
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
SEPARATED_LITERAL_SUFFIX,
@ -415,7 +394,6 @@ impl EarlyLintPass for MiscEarlyLints {
if let ExprKind::Lit(lit) = expr.kind {
MiscEarlyLints::check_lit(cx, lit, expr.span);
}
double_neg::check(cx, expr);
}
}

View file

@ -1,10 +0,0 @@
#[warn(clippy::double_neg)]
#[allow(clippy::no_effect)]
fn main() {
let x = 1;
-x;
-(-x);
--x;
//~^ ERROR: `--x` could be misinterpreted as pre-decrement by C programmers, is usually
//~| NOTE: `-D clippy::double-neg` implied by `-D warnings`
}

View file

@ -1,11 +0,0 @@
error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
--> tests/ui/double_neg.rs:7:5
|
LL | --x;
| ^^^
|
= note: `-D clippy::double-neg` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::double_neg)]`
error: aborting due to 1 previous error

View file

@ -13,9 +13,8 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
#![allow(clippy::manual_find_map)]
#![allow(clippy::manual_filter_map)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::manual_find_map)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::match_result_ok)]
@ -30,6 +29,7 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::panicking_overflow_checks)]
#![allow(clippy::needless_borrow)]
#![allow(clippy::reversed_empty_ranges)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_const_for_thread_local)]
@ -39,9 +39,11 @@
#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
#![allow(double_negations)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(useless_ptr_null_checks)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
@ -60,8 +62,6 @@
#![allow(unknown_lints)]
#![allow(unused_labels)]
#![allow(ambiguous_wide_pointer_comparisons)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::reversed_empty_ranges)]
#![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
#![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@ -74,9 +74,8 @@
#![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
#![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
#![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
#![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
#![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
#![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
@ -95,6 +94,7 @@
#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
#![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
#![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
#![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@ -104,9 +104,11 @@
#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
@ -128,6 +130,5 @@
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
#![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
fn main() {}

View file

@ -13,9 +13,8 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
#![allow(clippy::manual_find_map)]
#![allow(clippy::manual_filter_map)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::manual_find_map)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::match_result_ok)]
@ -30,6 +29,7 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::panicking_overflow_checks)]
#![allow(clippy::needless_borrow)]
#![allow(clippy::reversed_empty_ranges)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_const_for_thread_local)]
@ -39,9 +39,11 @@
#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
#![allow(double_negations)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(useless_ptr_null_checks)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
@ -60,8 +62,6 @@
#![allow(unknown_lints)]
#![allow(unused_labels)]
#![allow(ambiguous_wide_pointer_comparisons)]
#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::reversed_empty_ranges)]
#![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
#![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
#![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@ -74,9 +74,8 @@
#![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
#![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
#![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
#![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
#![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
#![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
@ -95,6 +94,7 @@
#![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
#![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
#![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
#![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
#![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
#![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@ -104,9 +104,11 @@
#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
@ -128,6 +130,5 @@
#![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
#![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
#![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
fn main() {}

View file

@ -73,132 +73,132 @@ error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_r
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
--> tests/ui/rename.rs:77:9
|
LL | #![warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
--> tests/ui/rename.rs:78:9
--> tests/ui/rename.rs:77:9
|
LL | #![warn(clippy::filter_map)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
--> tests/ui/rename.rs:79:9
error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
--> tests/ui/rename.rs:78:9
|
LL | #![warn(clippy::fn_address_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
LL | #![warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
--> tests/ui/rename.rs:80:9
--> tests/ui/rename.rs:79:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
--> tests/ui/rename.rs:81:9
--> tests/ui/rename.rs:80:9
|
LL | #![warn(clippy::if_let_redundant_pattern_matching)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
--> tests/ui/rename.rs:82:9
--> tests/ui/rename.rs:81:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
--> tests/ui/rename.rs:83:9
--> tests/ui/rename.rs:82:9
|
LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
--> tests/ui/rename.rs:84:9
--> tests/ui/rename.rs:83:9
|
LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
--> tests/ui/rename.rs:85:9
--> tests/ui/rename.rs:84:9
|
LL | #![warn(clippy::integer_arithmetic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
--> tests/ui/rename.rs:86:9
--> tests/ui/rename.rs:85:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
--> tests/ui/rename.rs:87:9
--> tests/ui/rename.rs:86:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
--> tests/ui/rename.rs:88:9
--> tests/ui/rename.rs:87:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
--> tests/ui/rename.rs:89:9
--> tests/ui/rename.rs:88:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
--> tests/ui/rename.rs:90:9
--> tests/ui/rename.rs:89:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> tests/ui/rename.rs:91:9
--> tests/ui/rename.rs:90:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
--> tests/ui/rename.rs:92:9
--> tests/ui/rename.rs:91:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
--> tests/ui/rename.rs:93:9
--> tests/ui/rename.rs:92:9
|
LL | #![warn(clippy::overflow_check_conditional)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
--> tests/ui/rename.rs:94:9
--> tests/ui/rename.rs:93:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
--> tests/ui/rename.rs:95:9
--> tests/ui/rename.rs:94:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> tests/ui/rename.rs:96:9
--> tests/ui/rename.rs:95:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
--> tests/ui/rename.rs:97:9
--> tests/ui/rename.rs:96:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
--> tests/ui/rename.rs:97:9
|
LL | #![warn(clippy::reverse_range_loop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
--> tests/ui/rename.rs:98:9
|
@ -253,155 +253,161 @@ error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
LL | #![warn(clippy::cmp_nan)]
| ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
error: lint `clippy::double_neg` has been renamed to `double_negations`
--> tests/ui/rename.rs:107:9
|
LL | #![warn(clippy::double_neg)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> tests/ui/rename.rs:108:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
--> tests/ui/rename.rs:108:9
--> tests/ui/rename.rs:109:9
|
LL | #![warn(clippy::drop_copy)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
error: lint `clippy::drop_ref` has been renamed to `dropping_references`
--> tests/ui/rename.rs:109:9
--> tests/ui/rename.rs:110:9
|
LL | #![warn(clippy::drop_ref)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
--> tests/ui/rename.rs:111:9
|
LL | #![warn(clippy::fn_address_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
--> tests/ui/rename.rs:110:9
--> tests/ui/rename.rs:112:9
|
LL | #![warn(clippy::fn_null_check)]
| ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
--> tests/ui/rename.rs:111:9
--> tests/ui/rename.rs:113:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
--> tests/ui/rename.rs:112:9
--> tests/ui/rename.rs:114:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
--> tests/ui/rename.rs:113:9
--> tests/ui/rename.rs:115:9
|
LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
--> tests/ui/rename.rs:114:9
--> tests/ui/rename.rs:116:9
|
LL | #![warn(clippy::forget_copy)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
--> tests/ui/rename.rs:115:9
--> tests/ui/rename.rs:117:9
|
LL | #![warn(clippy::forget_ref)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> tests/ui/rename.rs:116:9
--> tests/ui/rename.rs:118:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> tests/ui/rename.rs:117:9
--> tests/ui/rename.rs:119:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> tests/ui/rename.rs:118:9
--> tests/ui/rename.rs:120:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
--> tests/ui/rename.rs:119:9
--> tests/ui/rename.rs:121:9
|
LL | #![warn(clippy::invalid_utf8_in_unchecked)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
--> tests/ui/rename.rs:120:9
--> tests/ui/rename.rs:122:9
|
LL | #![warn(clippy::let_underscore_drop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
--> tests/ui/rename.rs:121:9
--> tests/ui/rename.rs:123:9
|
LL | #![warn(clippy::maybe_misused_cfg)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
--> tests/ui/rename.rs:122:9
--> tests/ui/rename.rs:124:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
--> tests/ui/rename.rs:123:9
--> tests/ui/rename.rs:125:9
|
LL | #![warn(clippy::mismatched_target_os)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> tests/ui/rename.rs:124:9
--> tests/ui/rename.rs:126:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
--> tests/ui/rename.rs:125:9
--> tests/ui/rename.rs:127:9
|
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
--> tests/ui/rename.rs:126:9
--> tests/ui/rename.rs:128:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
--> tests/ui/rename.rs:127:9
--> tests/ui/rename.rs:129:9
|
LL | #![warn(clippy::undropped_manually_drops)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> tests/ui/rename.rs:128:9
--> tests/ui/rename.rs:130:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> tests/ui/rename.rs:129:9
--> tests/ui/rename.rs:131:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
--> tests/ui/rename.rs:130:9
--> tests/ui/rename.rs:132:9
|
LL | #![warn(clippy::vtable_address_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
--> tests/ui/rename.rs:131:9
|
LL | #![warn(clippy::reverse_range_loop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
error: aborting due to 67 previous errors
error: aborting due to 68 previous errors

6
tests/crashes/108428.rs Normal file
View file

@ -0,0 +1,6 @@
//@ known-bug: #108428
//@ needs-rustc-debug-assertions
//@ compile-flags: -Wunused-lifetimes
fn main() {
let _: extern fn<'a: 'static>();
}

10
tests/crashes/132826.rs Normal file
View file

@ -0,0 +1,10 @@
//@ known-bug: #132826
pub trait MyTrait {
type Item;
}
impl<K> MyTrait for Vec<K> {
type Item = Vec<K>;
}
impl<K> From<Vec<K>> for <Vec<K> as MyTrait>::Item {}

View file

@ -1,11 +0,0 @@
//@ known-bug: #135020
pub fn problem_thingy(items: &mut impl Iterator<Item = str>) {
let mut peeker = items.peekable();
match peeker.peek() {
Some(_) => (),
None => return (),
}
}
pub fn main() {}

View file

@ -37,7 +37,8 @@ pub struct Y(u8);
pub struct Z;
// We can't compute layout for generic types.
//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters'
//@ hasraw type_layout/struct.Generic.html 'Unable to compute type layout, possibly due to this type having generic parameters.'
//@ hasraw type_layout/struct.Generic.html 'Layout can only be computed for concrete, fully-instantiated types.'
//@ !hasraw - 'Size: '
pub struct Generic<T>(T);
@ -91,3 +92,9 @@ pub enum Uninhabited {}
//@ hasraw type_layout/struct.Uninhabited2.html 'Size: '
//@ hasraw - '8 bytes (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)'
pub struct Uninhabited2(std::convert::Infallible, u64);
pub trait Project { type Assoc; }
// We can't compute layout. A `LayoutError::Unknown` is returned.
//@ hasraw type_layout/struct.Unknown.html 'Unable to compute type layout.'
//@ !hasraw - 'Size: '
pub struct Unknown(<() as Project>::Assoc) where for<'a> (): Project;

View file

@ -6,7 +6,7 @@ union Foo {
enum Bar {
Boo = {
let _: Option<Foo> = None;
let _: Option<Foo> = None; //~ ERROR evaluation of constant value failed
0
},
}

View file

@ -45,7 +45,13 @@ help: wrap the field type in `ManuallyDrop<...>`
LL | a: std::mem::ManuallyDrop<str>,
| +++++++++++++++++++++++ +
error: aborting due to 4 previous errors
error[E0080]: evaluation of constant value failed
--> $DIR/eval-error.rs:9:30
|
LL | let _: Option<Foo> = None;
| ^^^^ the type `Foo` has an unknown layout
Some errors have detailed explanations: E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0277`.
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0080, E0277, E0517, E0740.
For more information about an error, try `rustc --explain E0080`.

View file

@ -24,7 +24,7 @@ impl<T, const L: u8> VirtualWrapper<T, L> {
impl<T: MyTrait + 'static, const L: u8> MyTrait for VirtualWrapper<T, L> {
fn virtualize(&self) -> &dyn MyTrait {
unsafe { virtualize_my_trait(L, self) }
// unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem
// unsafe { virtualize_my_trait(L, &self.0) } // <-- this code fixes the problem
}
}

View file

@ -8,6 +8,7 @@ struct S {
}
const C: S = unsafe { std::mem::transmute(()) };
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
const _: [(); {
C;
0

View file

@ -16,6 +16,16 @@ help: the `Box` type always has a statically known size and allocates its conten
LL | a: Box<[u8]>,
| ++++ +
error: aborting due to 1 previous error
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
--> $DIR/base-layout-is-sized-ice-123078.rs:10:23
|
LL | const C: S = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^
|
= note: source type: `()` (0 bits)
= note: target type: `S` (the type `S` has an unknown layout)
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0512.
For more information about an error, try `rustc --explain E0277`.

View file

@ -10,5 +10,6 @@ struct LazyLock {
}
static EMPTY_SET: LazyLock = todo!();
//~^ ERROR could not evaluate static initializer
fn main() {}

View file

@ -7,6 +7,13 @@ LL | data: (dyn Sync, ()),
= help: the trait `Sized` is not implemented for `(dyn Sync + 'static)`
= note: only the last element of a tuple may have a dynamically sized type
error: aborting due to 1 previous error
error[E0080]: could not evaluate static initializer
--> $DIR/invalid-unsized-const-eval.rs:12:1
|
LL | static EMPTY_SET: LazyLock = todo!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `(dyn Sync, ())` has an unknown layout
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -18,6 +18,20 @@ LL | struct MySlice<T>(T);
| |
| this could be changed to `T: ?Sized`...
error: aborting due to 1 previous error
error[E0080]: could not evaluate static initializer
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
= note: the type `MySlice<[bool]>` has an unknown layout
|
note: inside `align_of::<P2>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
note: inside `CHECK`
--> $DIR/invalid-unsized-in-always-sized-tail.rs:15:28
|
LL | static CHECK: () = assert!(align_of::<P2>() == 1);
| ^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -6,5 +6,6 @@ struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
//~^ ERROR the size for values of type `V` cannot be known at compilation time
const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
//~^ ERROR evaluation of constant value failed
pub fn main() {}

View file

@ -22,6 +22,13 @@ help: the `Box` type always has a statically known size and allocates its conten
LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U);
| ++++ +
error: aborting due to 1 previous error
error[E0080]: evaluation of constant value failed
--> $DIR/issue-unsized-tail-restatic-ice-122488.rs:8:1
|
LL | const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `ArenaSet<Vec<u8>, [u8]>` has an unknown layout
For more information about this error, try `rustc --explain E0277`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0277.
For more information about an error, try `rustc --explain E0080`.

View file

@ -0,0 +1,11 @@
#![feature(trivial_bounds)]
fn return_str()
where
str: Sized,
{
[(); { let _a: Option<str> = None; 0 }];
//~^ ERROR evaluation of constant value failed
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: evaluation of constant value failed
--> $DIR/uncomputable-due-to-trivial-bounds-ice-135138.rs:7:16
|
LL | [(); { let _a: Option<str> = None; 0 }];
| ^^ the type `Option<str>` has an unknown layout
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,7 @@
//@ check-pass
fn problem_thingy(items: &mut impl Iterator<Item = str>) {
items.peekable();
}
fn main() {}

View file

@ -0,0 +1,14 @@
#![feature(trivial_bounds)]
//@ error-pattern: error[E0080]: evaluation of constant value failed
//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout
trait Project {
type Assoc;
}
fn foo() where (): Project {
[(); size_of::<<() as Project>::Assoc>()];
}
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
= note: the type `<() as Project>::Assoc` has an unknown layout
|
note: inside `std::mem::size_of::<<() as Project>::Assoc>`
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
note: inside `foo::{constant#0}`
--> $DIR/unknown-when-no-type-parameter.rs:11:10
|
LL | [(); size_of::<<() as Project>::Assoc>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,12 @@
#![feature(ptr_metadata)]
#![feature(trivial_bounds)]
fn return_str()
where
str: std::ptr::Pointee<Metadata = str>,
{
[(); { let _a: Option<&str> = None; 0 }];
//~^ ERROR evaluation of constant value failed
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0080]: evaluation of constant value failed
--> $DIR/unknown-when-ptr-metadata-is-DST.rs:8:16
|
LL | [(); { let _a: Option<&str> = None; 0 }];
| ^^ the type `str` has an unknown layout
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0080`.

View file

@ -0,0 +1,9 @@
//@ check-pass
fn main() {
let x = 1;
-x;
-(-x);
--x; //~ WARN use of a double negation
---x; //~ WARN use of a double negation
let _y = --(-x); //~ WARN use of a double negation
}

View file

@ -0,0 +1,42 @@
warning: use of a double negation
--> $DIR/lint-double-negations.rs:6:5
|
LL | --x;
| ^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
= note: `#[warn(double_negations)]` on by default
help: add parentheses for clarity
|
LL | -(-x);
| + +
warning: use of a double negation
--> $DIR/lint-double-negations.rs:7:6
|
LL | ---x;
| ^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
help: add parentheses for clarity
|
LL | --(-x);
| + +
warning: use of a double negation
--> $DIR/lint-double-negations.rs:8:14
|
LL | let _y = --(-x);
| ^^^^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
help: add parentheses for clarity
|
LL | let _y = -(-(-x));
| + +
warning: 3 warnings emitted

View file

@ -4,6 +4,7 @@
fn main() {
let x2: i8 = --128; //~ ERROR literal out of range for `i8`
//~| WARN use of a double negation
let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32`

View file

@ -1,3 +1,17 @@
warning: use of a double negation
--> $DIR/lint-type-overflow2.rs:6:18
|
LL | let x2: i8 = --128;
| ^^^^^
|
= note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages
= note: use `-= 1` if you meant to decrement the value
= note: `#[warn(double_negations)]` on by default
help: add parentheses for clarity
|
LL | let x2: i8 = -(-128);
| + +
error: literal out of range for `i8`
--> $DIR/lint-type-overflow2.rs:6:20
|
@ -13,7 +27,7 @@ LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:8:14
--> $DIR/lint-type-overflow2.rs:9:14
|
LL | let x = -3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
@ -21,7 +35,7 @@ LL | let x = -3.40282357e+38_f32;
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:9:14
--> $DIR/lint-type-overflow2.rs:10:14
|
LL | let x = 3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
@ -29,7 +43,7 @@ LL | let x = 3.40282357e+38_f32;
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:10:14
--> $DIR/lint-type-overflow2.rs:11:14
|
LL | let x = -1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -37,12 +51,12 @@ LL | let x = -1.7976931348623159e+308_f64;
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:11:14
--> $DIR/lint-type-overflow2.rs:12:14
|
LL | let x = 1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
error: aborting due to 5 previous errors
error: aborting due to 5 previous errors; 1 warning emitted

View file

@ -13,6 +13,6 @@ struct Other {
fn main() {
unsafe {
std::mem::transmute::<Option<()>, Option<&Other>>(None);
//~^ ERROR cannot transmute
//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
}
}

View file

@ -1025,7 +1025,8 @@ users_on_vacation = [
"nnethercote",
"spastorino",
"workingjubilee",
"kobzol"
"kobzol",
"jieyouxu",
]
[[assign.warn_non_default_branch.exceptions]]