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:
commit
55459598c2
67 changed files with 974 additions and 576 deletions
|
|
@ -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, .. }])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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))) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ early_lint_methods!(
|
|||
UnusedDocComment: UnusedDocComment,
|
||||
Expr2024: Expr2024,
|
||||
Precedence: Precedence,
|
||||
DoubleNegations: DoubleNegations,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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}'
|
||||
|
|
|
|||
|
|
@ -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> },
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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
260
library/std/src/io/pipe.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
18
library/std/src/io/pipe/tests.rs
Normal file
18
library/std/src/io/pipe/tests.rs
Normal 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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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]:
|
||||
|
||||

|
||||
```
|
||||
$ 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 |
|
|
@ -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; {#+ #}
|
||||
|
|
|
|||
6
src/tools/clippy/.github/driver.sh
vendored
6
src/tools/clippy/.github/driver.sh
vendored
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 = ""]
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
6
tests/crashes/108428.rs
Normal 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
10
tests/crashes/132826.rs
Normal 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 {}
|
||||
|
|
@ -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() {}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ union Foo {
|
|||
|
||||
enum Bar {
|
||||
Boo = {
|
||||
let _: Option<Foo> = None;
|
||||
let _: Option<Foo> = None; //~ ERROR evaluation of constant value failed
|
||||
0
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ struct LazyLock {
|
|||
}
|
||||
|
||||
static EMPTY_SET: LazyLock = todo!();
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
@ -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`.
|
||||
7
tests/ui/layout/unexpected-unsized-field-issue-135020.rs
Normal file
7
tests/ui/layout/unexpected-unsized-field-issue-135020.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//@ check-pass
|
||||
|
||||
fn problem_thingy(items: &mut impl Iterator<Item = str>) {
|
||||
items.peekable();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
14
tests/ui/layout/unknown-when-no-type-parameter.rs
Normal file
14
tests/ui/layout/unknown-when-no-type-parameter.rs
Normal 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() {}
|
||||
16
tests/ui/layout/unknown-when-no-type-parameter.stderr
Normal file
16
tests/ui/layout/unknown-when-no-type-parameter.stderr
Normal 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`.
|
||||
12
tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs
Normal file
12
tests/ui/layout/unknown-when-ptr-metadata-is-DST.rs
Normal 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() {}
|
||||
9
tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr
Normal file
9
tests/ui/layout/unknown-when-ptr-metadata-is-DST.stderr
Normal 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`.
|
||||
9
tests/ui/lint/lint-double-negations.rs
Normal file
9
tests/ui/lint/lint-double-negations.rs
Normal 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
|
||||
}
|
||||
42
tests/ui/lint/lint-double-negations.stderr
Normal file
42
tests/ui/lint/lint-double-negations.stderr
Normal 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
|
||||
|
||||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,8 @@ users_on_vacation = [
|
|||
"nnethercote",
|
||||
"spastorino",
|
||||
"workingjubilee",
|
||||
"kobzol"
|
||||
"kobzol",
|
||||
"jieyouxu",
|
||||
]
|
||||
|
||||
[[assign.warn_non_default_branch.exceptions]]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue