diff options
50 files changed, 1075 insertions, 201 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 210ec72a11e..f87aecb6876 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -383,25 +383,15 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 JEMALLOC_SYS_WITH_LG_PAGE: 14 os: macos-latest - - name: x86_64-msvc-1 + - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" - SCRIPT: make ci-subset-1 + SCRIPT: make ci-msvc os: windows-2019-8core-32gb - - name: x86_64-msvc-2 - env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" - SCRIPT: make ci-subset-2 - os: windows-2019-8core-32gb - - name: i686-msvc-1 - env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" - SCRIPT: make ci-subset-1 - os: windows-2019-8core-32gb - - name: i686-msvc-2 + - name: i686-msvc env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc" - SCRIPT: make ci-subset-2 + SCRIPT: make ci-msvc os: windows-2019-8core-32gb - name: x86_64-msvc-cargo env: diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6e15f06a76d..ba47ebd68cb 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -67,7 +67,7 @@ struct ArenaChunk<T = u8> { unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> { fn drop(&mut self) { - unsafe { Box::from_raw(self.storage.as_mut()) }; + unsafe { drop(Box::from_raw(self.storage.as_mut())) } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index ac9e7d06c4e..83b7e13905a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -32,6 +32,10 @@ pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { State::new().bounds_to_string(bounds) } +pub fn where_bound_predicate_to_string(where_bound_predicate: &ast::WhereBoundPredicate) -> String { + State::new().where_bound_predicate_to_string(where_bound_predicate) +} + pub fn pat_to_string(pat: &ast::Pat) -> String { State::new().pat_to_string(pat) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3f80728a260..59239b49edd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -824,6 +824,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere Self::to_string(|s| s.print_type_bounds(bounds)) } + fn where_bound_predicate_to_string( + &self, + where_bound_predicate: &ast::WhereBoundPredicate, + ) -> String { + Self::to_string(|s| s.print_where_bound_predicate(where_bound_predicate)) + } + fn pat_to_string(&self, pat: &ast::Pat) -> String { Self::to_string(|s| s.print_pat(pat)) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c465f8c948a..5c01b7ea70a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -623,19 +623,8 @@ impl<'a> State<'a> { pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { match predicate { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - bound_generic_params, - bounded_ty, - bounds, - .. - }) => { - self.print_formal_generic_params(bound_generic_params); - self.print_type(bounded_ty); - self.word(":"); - if !bounds.is_empty() { - self.nbsp(); - self.print_type_bounds(bounds); - } + ast::WherePredicate::BoundPredicate(where_bound_predicate) => { + self.print_where_bound_predicate(where_bound_predicate); } ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { lifetime, @@ -658,6 +647,19 @@ impl<'a> State<'a> { } } + pub fn print_where_bound_predicate( + &mut self, + where_bound_predicate: &ast::WhereBoundPredicate, + ) { + self.print_formal_generic_params(&where_bound_predicate.bound_generic_params); + self.print_type(&where_bound_predicate.bounded_ty); + self.word(":"); + if !where_bound_predicate.bounds.is_empty() { + self.nbsp(); + self.print_type_bounds(&where_bound_predicate.bounds); + } + } + fn print_use_tree(&mut self, tree: &ast::UseTree) { match &tree.kind { ast::UseTreeKind::Simple(rename) => { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5e13ee7b8a4..34b7e09576a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -425,6 +425,7 @@ lint_overflowing_bin_hex = literal out of range for `{$ty}` .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}` .positive_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` .suggestion = consider using the type `{$suggestion_ty}` instead + .sign_bit_suggestion = to use as a negative number (decimal `{$negative_val}`), consider using the type `{$uint_ty}` for the literal and cast it to `{$int_ty}` .help = consider using the type `{$suggestion_ty}` instead lint_overflowing_int = literal out of range for `{$ty}` @@ -478,13 +479,11 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name} lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target .label = target type is set here -lint_suspicious_double_ref_op = - using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op -> - *[should_not_happen] [{$op}] - [deref] dereferencing - [borrow] borrowing - [clone] cloning - } the inner type +lint_suspicious_double_ref_clone = + using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type + +lint_suspicious_double_ref_deref = + using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type lint_trivial_untranslatable_diag = diagnostic with static strings only diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index e990c771bdf..49597516b36 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1231,11 +1231,15 @@ pub struct NoopMethodCallDiag<'a> { } #[derive(LintDiagnostic)] -#[diag(lint_suspicious_double_ref_op)] -pub struct SuspiciousDoubleRefDiag<'a> { - pub call: Symbol, +#[diag(lint_suspicious_double_ref_deref)] +pub struct SuspiciousDoubleRefDerefDiag<'a> { + pub ty: Ty<'a>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_suspicious_double_ref_clone)] +pub struct SuspiciousDoubleRefCloneDiag<'a> { pub ty: Ty<'a>, - pub op: &'static str, } // pass_by_value.rs @@ -1342,6 +1346,8 @@ pub struct OverflowingBinHex<'a> { pub sign: OverflowingBinHexSign, #[subdiagnostic] pub sub: Option<OverflowingBinHexSub<'a>>, + #[subdiagnostic] + pub sign_bit_sub: Option<OverflowingBinHexSignBitSub<'a>>, } pub enum OverflowingBinHexSign { @@ -1386,6 +1392,21 @@ pub enum OverflowingBinHexSub<'a> { Help { suggestion_ty: &'a str }, } +#[derive(Subdiagnostic)] +#[suggestion( + lint_sign_bit_suggestion, + code = "{lit_no_suffix}{uint_ty} as {int_ty}", + applicability = "maybe-incorrect" +)] +pub struct OverflowingBinHexSignBitSub<'a> { + #[primary_span] + pub span: Span, + pub lit_no_suffix: &'a str, + pub negative_val: String, + pub uint_ty: &'a str, + pub int_ty: &'a str, +} + #[derive(LintDiagnostic)] #[diag(lint_overflowing_int)] #[note] @@ -1534,8 +1555,29 @@ pub struct UnusedOp<'a> { pub op: &'a str, #[label] pub label: Span, - #[suggestion(style = "verbose", code = "let _ = ", applicability = "maybe-incorrect")] - pub suggestion: Span, + #[subdiagnostic] + pub suggestion: UnusedOpSuggestion, +} + +#[derive(Subdiagnostic)] +pub enum UnusedOpSuggestion { + #[suggestion( + lint_suggestion, + style = "verbose", + code = "let _ = ", + applicability = "maybe-incorrect" + )] + NormalExpr { + #[primary_span] + span: Span, + }, + #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")] + BlockTailExpr { + #[suggestion_part(code = "let _ = ")] + before_span: Span, + #[suggestion_part(code = ";")] + after_span: Span, + }, } #[derive(LintDiagnostic)] @@ -1578,15 +1620,25 @@ pub struct UnusedDef<'a, 'b> { } #[derive(Subdiagnostic)] -#[suggestion( - lint_suggestion, - style = "verbose", - code = "let _ = ", - applicability = "maybe-incorrect" -)] -pub struct UnusedDefSuggestion { - #[primary_span] - pub span: Span, + +pub enum UnusedDefSuggestion { + #[suggestion( + lint_suggestion, + style = "verbose", + code = "let _ = ", + applicability = "maybe-incorrect" + )] + NormalExpr { + #[primary_span] + span: Span, + }, + #[multipart_suggestion(lint_suggestion, style = "verbose", applicability = "maybe-incorrect")] + BlockTailExpr { + #[suggestion_part(code = "let _ = ")] + before_span: Span, + #[suggestion_part(code = ";")] + after_span: Span, + }, } // Needed because of def_path_str diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index d054966459d..d56c35bb677 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -1,5 +1,7 @@ use crate::context::LintContext; -use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag}; +use crate::lints::{ + NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag, +}; use crate::LateContext; use crate::LateLintPass; use rustc_hir::def::DefKind; @@ -76,22 +78,22 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` // traits and ignore any other method call. - let did = match cx.typeck_results().type_dependent_def(expr.hir_id) { - // Verify we are dealing with a method/associated function. - Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { - // Check that we're dealing with a trait method for one of the traits we care about. - Some(trait_id) - if matches!( - cx.tcx.get_diagnostic_name(trait_id), - Some(sym::Borrow | sym::Clone | sym::Deref) - ) => - { - did - } - _ => return, - }, - _ => return, + + let Some((DefKind::AssocFn, did)) = + cx.typeck_results().type_dependent_def(expr.hir_id) + else { + return; + }; + + let Some(trait_id) = cx.tcx.trait_of_item(did) else { return }; + + if !matches!( + cx.tcx.get_diagnostic_name(trait_id), + Some(sym::Borrow | sym::Clone | sym::Deref) + ) { + return; }; + let substs = cx .tcx .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id)); @@ -102,13 +104,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { // (Re)check that it implements the noop diagnostic. let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return }; - let op = match name { - sym::noop_method_borrow => "borrow", - sym::noop_method_clone => "clone", - sym::noop_method_deref => "deref", - _ => return, - }; - let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); let arg_adjustments = cx.typeck_results().expr_adjustments(receiver); @@ -129,11 +124,22 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span }, ); } else { - cx.emit_spanned_lint( - SUSPICIOUS_DOUBLE_REF_OP, - span, - SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op }, - ) + match name { + // If `type_of(x) == T` and `x.borrow()` is used to get `&T`, + // then that should be allowed + sym::noop_method_borrow => return, + sym::noop_method_clone => cx.emit_spanned_lint( + SUSPICIOUS_DOUBLE_REF_OP, + span, + SuspiciousDoubleRefCloneDiag { ty: expr_ty }, + ), + sym::noop_method_deref => cx.emit_spanned_lint( + SUSPICIOUS_DOUBLE_REF_OP, + span, + SuspiciousDoubleRefDerefDiag { ty: expr_ty }, + ), + _ => return, + } } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 264a59c5585..ec9e7c7fdae 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -3,9 +3,10 @@ use crate::{ lints::{ AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, - OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSub, - OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, - RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag, + OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub, + OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, + OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange, + VariantSizeDifferencesDiag, }, }; use crate::{LateContext, LateLintPass, LintContext}; @@ -297,10 +298,50 @@ fn report_bin_hex_error( } }, ); + let sign_bit_sub = (!negative) + .then(|| { + let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else { + return None; + }; + + let Some(bit_width) = int_ty.bit_width() else { + return None; // isize case + }; + + // Skip if sign bit is not set + if (val & (1 << (bit_width - 1))) == 0 { + return None; + } + + let lit_no_suffix = + if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { + repr_str.split_at(pos).0 + } else { + &repr_str + }; + + Some(OverflowingBinHexSignBitSub { + span: expr.span, + lit_no_suffix, + negative_val: actually.clone(), + int_ty: int_ty.name_str(), + uint_ty: int_ty.to_unsigned().name_str(), + }) + }) + .flatten(); + cx.emit_spanned_lint( OVERFLOWING_LITERALS, expr.span, - OverflowingBinHex { ty: t, lit: repr_str.clone(), dec: val, actually, sign, sub }, + OverflowingBinHex { + ty: t, + lit: repr_str.clone(), + dec: val, + actually, + sign, + sub, + sign_bit_sub, + }, ) } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 04df23c736b..9861610612f 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1,7 +1,8 @@ use crate::lints::{ PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag, UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim, - UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedResult, + UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion, + UnusedResult, }; use crate::Lint; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; @@ -93,7 +94,15 @@ declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'tcx> LateLintPass<'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) { - let hir::StmtKind::Semi(expr) = s.kind else { return; }; + let hir::StmtKind::Semi(mut expr) = s.kind else { return; }; + + let mut expr_is_from_block = false; + while let hir::ExprKind::Block(blk, ..) = expr.kind + && let hir::Block { expr: Some(e), .. } = blk + { + expr = e; + expr_is_from_block = true; + } if let hir::ExprKind::Ret(..) = expr.kind { return; @@ -113,6 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { expr.span, "output of future returned by ", "", + expr_is_from_block, ) { // We have a bare `foo().await;` on an opaque type from an async function that was @@ -125,13 +135,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span); let type_lint_emitted_or_suppressed = match must_use_result { Some(path) => { - emit_must_use_untranslated(cx, &path, "", "", 1, false); + emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block); true } None => false, }; - let fn_warned = check_fn_must_use(cx, expr); + let fn_warned = check_fn_must_use(cx, expr, expr_is_from_block); if !fn_warned && type_lint_emitted_or_suppressed { // We don't warn about unused unit or uninhabited types. @@ -176,7 +186,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { UnusedOp { op: must_use_op, label: expr.span, - suggestion: expr.span.shrink_to_lo(), + suggestion: if expr_is_from_block { + UnusedOpSuggestion::BlockTailExpr { + before_span: expr.span.shrink_to_lo(), + after_span: expr.span.shrink_to_hi(), + } + } else { + UnusedOpSuggestion::NormalExpr { span: expr.span.shrink_to_lo() } + }, }, ); op_warned = true; @@ -186,7 +203,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx.emit_spanned_lint(UNUSED_RESULTS, s.span, UnusedResult { ty }); } - fn check_fn_must_use(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + fn check_fn_must_use( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + expr_is_from_block: bool, + ) -> bool { let maybe_def_id = match expr.kind { hir::ExprKind::Call(ref callee, _) => { match callee.kind { @@ -207,7 +228,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { _ => None, }; if let Some(def_id) = maybe_def_id { - check_must_use_def(cx, def_id, expr.span, "return value of ", "") + check_must_use_def( + cx, + def_id, + expr.span, + "return value of ", + "", + expr_is_from_block, + ) } else { false } @@ -350,6 +378,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { span: Span, descr_pre_path: &str, descr_post_path: &str, + expr_is_from_block: bool, ) -> bool { is_def_must_use(cx, def_id, span) .map(|must_use_path| { @@ -360,6 +389,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post_path, 1, false, + expr_is_from_block, ) }) .is_some() @@ -373,6 +403,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post: &str, plural_len: usize, is_inner: bool, + expr_is_from_block: bool, ) { let plural_suffix = pluralize!(plural_len); @@ -380,21 +411,51 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { MustUsePath::Suppressed => {} MustUsePath::Boxed(path) => { let descr_pre = &format!("{}boxed ", descr_pre); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::Opaque(path) => { let descr_pre = &format!("{}implementer{} of ", descr_pre, plural_suffix); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::TraitObject(path) => { let descr_post = &format!(" trait object{}{}", plural_suffix, descr_post); - emit_must_use_untranslated(cx, path, descr_pre, descr_post, plural_len, true); + emit_must_use_untranslated( + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, + ); } MustUsePath::TupleElement(elems) => { for (index, path) in elems { let descr_post = &format!(" in tuple element {}", index); emit_must_use_untranslated( - cx, path, descr_pre, descr_post, plural_len, true, + cx, + path, + descr_pre, + descr_post, + plural_len, + true, + expr_is_from_block, ); } } @@ -407,6 +468,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { descr_post, plural_len.saturating_add(usize::try_from(*len).unwrap_or(usize::MAX)), true, + expr_is_from_block, ); } MustUsePath::Closure(span) => { @@ -433,8 +495,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { cx, def_id: *def_id, note: *reason, - suggestion: (!is_inner) - .then_some(UnusedDefSuggestion { span: span.shrink_to_lo() }), + suggestion: (!is_inner).then_some(if expr_is_from_block { + UnusedDefSuggestion::BlockTailExpr { + before_span: span.shrink_to_lo(), + after_span: span.shrink_to_hi(), + } + } else { + UnusedDefSuggestion::NormalExpr { span: span.shrink_to_lo() } + }), }, ); } diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index f53dc8cb0ec..ae32a54be3d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -95,7 +95,10 @@ impl<'tcx> TyCtxt<'tcx> { // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { - assert!(matches!(self.def_kind(ct.def), DefKind::AnonConst)); + assert!(matches!( + self.def_kind(ct.def), + DefKind::InlineConst | DefKind::AnonConst + )); let mir_body = self.mir_for_ctfe(ct.def); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 1fe8ea07892..ef64f70fdf3 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -9,6 +9,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut}; use rustc_session::Session; +use rustc_target::spec::PanicStrategy; pub struct CheckAlignment; @@ -236,7 +237,11 @@ fn insert_alignment_check<'tcx>( required: Operand::Copy(alignment), found: Operand::Copy(addr), }), - unwind: UnwindAction::Terminate, + unwind: if tcx.sess.panic_strategy() == PanicStrategy::Unwind { + UnwindAction::Terminate + } else { + UnwindAction::Unreachable + }, }, }); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e4b01ef2b17..7284b33f09d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_ast::{ self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind, DUMMY_NODE_ID, }; -use rustc_ast_pretty::pprust::path_segment_to_string; +use rustc_ast_pretty::pprust::where_bound_predicate_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, @@ -1050,7 +1050,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { }; // Confirm that the target is an associated type. - let (ty, position, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { + let (ty, _, path) = if let ast::TyKind::Path(Some(qself), path) = &bounded_ty.kind { // use this to verify that ident is a type param. let Some(partial_res) = self.r.partial_res_map.get(&bounded_ty.id) else { return false; @@ -1079,7 +1079,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { return false; } if let ( - [ast::PathSegment { ident: constrain_ident, args: None, .. }], + [ast::PathSegment { args: None, .. }], [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)], ) = (&type_param_path.segments[..], &bounds[..]) { @@ -1087,29 +1087,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { &poly_trait_ref.trait_ref.path.segments[..] { if ident.span == span { + let Some(new_where_bound_predicate) = mk_where_bound_predicate(path, poly_trait_ref, ty) else { return false; }; err.span_suggestion_verbose( *where_span, format!("constrain the associated type to `{}`", ident), - format!( - "{}: {}<{} = {}>", - self.r - .tcx - .sess - .source_map() - .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`. - .unwrap_or_else(|_| constrain_ident.to_string()), - path.segments[..position] - .iter() - .map(|segment| path_segment_to_string(segment)) - .collect::<Vec<_>>() - .join("::"), - path.segments[position..] - .iter() - .map(|segment| path_segment_to_string(segment)) - .collect::<Vec<_>>() - .join("::"), - ident, - ), + where_bound_predicate_to_string(&new_where_bound_predicate), Applicability::MaybeIncorrect, ); } @@ -2605,6 +2587,70 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } +fn mk_where_bound_predicate( + path: &Path, + poly_trait_ref: &ast::PolyTraitRef, + ty: &ast::Ty, +) -> Option<ast::WhereBoundPredicate> { + use rustc_span::DUMMY_SP; + let modified_segments = { + let mut segments = path.segments.clone(); + let [preceding @ .., second_last, last] = segments.as_mut_slice() else { return None; }; + let mut segments = ThinVec::from(preceding); + + let added_constraint = ast::AngleBracketedArg::Constraint(ast::AssocConstraint { + id: DUMMY_NODE_ID, + ident: last.ident, + gen_args: None, + kind: ast::AssocConstraintKind::Equality { + term: ast::Term::Ty(ast::ptr::P(ast::Ty { + kind: ast::TyKind::Path(None, poly_trait_ref.trait_ref.path.clone()), + id: DUMMY_NODE_ID, + span: DUMMY_SP, + tokens: None, + })), + }, + span: DUMMY_SP, + }); + + match second_last.args.as_deref_mut() { + Some(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { args, .. })) => { + args.push(added_constraint); + } + Some(_) => return None, + None => { + second_last.args = + Some(ast::ptr::P(ast::GenericArgs::AngleBracketed(ast::AngleBracketedArgs { + args: ThinVec::from([added_constraint]), + span: DUMMY_SP, + }))); + } + } + + segments.push(second_last.clone()); + segments + }; + + let new_where_bound_predicate = ast::WhereBoundPredicate { + span: DUMMY_SP, + bound_generic_params: ThinVec::new(), + bounded_ty: ast::ptr::P(ty.clone()), + bounds: vec![ast::GenericBound::Trait( + ast::PolyTraitRef { + bound_generic_params: ThinVec::new(), + trait_ref: ast::TraitRef { + path: ast::Path { segments: modified_segments, span: DUMMY_SP, tokens: None }, + ref_id: DUMMY_NODE_ID, + }, + span: DUMMY_SP, + }, + ast::TraitBoundModifier::None, + )], + }; + + Some(new_where_bound_predicate) +} + /// Report lifetime/lifetime shadowing as an error. pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) { let mut err = struct_span_err!( diff --git a/config.example.toml b/config.example.toml index d0eaa9fd7ff..0c65b25fe13 100644 --- a/config.example.toml +++ b/config.example.toml @@ -250,6 +250,13 @@ changelog-seen = 2 # target when running tests, otherwise this can be omitted. #nodejs = "node" +# The npm executable to use. Note that this is used for rustdoc-gui tests, +# otherwise this can be omitted. +# +# Under Windows this should be `npm.cmd` or path to it (verified on nodejs v18.06), or +# error will be emitted. +#npm = "npm" + # Python interpreter to use for various tasks throughout the build, notably # rustdoc tests, the lldb python interpreter, and some dist bits and pieces. # diff --git a/library/core/benches/slice.rs b/library/core/benches/slice.rs index 9b86a0ca97c..3bfb35e684e 100644 --- a/library/core/benches/slice.rs +++ b/library/core/benches/slice.rs @@ -1,3 +1,4 @@ +use core::ptr::NonNull; use test::black_box; use test::Bencher; @@ -162,3 +163,11 @@ fn fill_byte_sized(b: &mut Bencher) { black_box(slice.fill(black_box(NewType(42)))); }); } + +// Tests the ability of the compiler to recognize that only the last slice item is needed +// based on issue #106288 +#[bench] +fn fold_to_last(b: &mut Bencher) { + let slice: &[i32] = &[0; 1024]; + b.iter(|| black_box(slice).iter().fold(None, |_, r| Some(NonNull::from(r)))); +} diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c4134dbcd25..45e5b76272e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -960,6 +960,8 @@ pub(crate) mod builtin { /// /// A compile time error is never emitted when using this macro regardless /// of whether the environment variable is present or not. + /// To emit a compile error if the environment variable is not present, + /// use the [`env!`] macro instead. /// /// # Examples /// diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 8266e899011..80289ca08c3 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -308,7 +308,7 @@ mod prim_never {} /// /// ```no_run /// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }; +/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// /// USVs are also the exact set of values that may be encoded in UTF-8. Because diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 3462c0e020a..96a145e22ed 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -191,6 +191,39 @@ macro_rules! iterator { self.next_back() } + #[inline] + fn fold<B, F>(self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + // this implementation consists of the following optimizations compared to the + // default implementation: + // - do-while loop, as is llvm's preferred loop shape, + // see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops + // - bumps an index instead of a pointer since the latter case inhibits + // some optimizations, see #111603 + // - avoids Option wrapping/matching + if is_empty!(self) { + return init; + } + let mut acc = init; + let mut i = 0; + let len = len!(self); + loop { + // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of + // the slice allocation + acc = f(acc, unsafe { & $( $mut_ )? *self.ptr.add(i).as_ptr() }); + // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the + // slice had that length, in which case we'll break out of the loop + // after the increment + i = unsafe { i.unchecked_add(1) }; + if i == len { + break; + } + } + acc + } + // We override the default implementation, which uses `try_fold`, // because this simple implementation generates less LLVM IR and is // faster to compile. diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index c02cd99cc44..ee885adfeee 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1001,7 +1001,7 @@ fn nonnull_tagged_pointer_with_provenance() { assert_eq!(p.tag(), 3); assert_eq!(unsafe { *p.pointer().as_ptr() }, 10); - unsafe { Box::from_raw(p.pointer().as_ptr()) }; + unsafe { drop(Box::from_raw(p.pointer().as_ptr())) }; /// A non-null pointer type which carries several bits of metadata and maintains provenance. #[repr(transparent)] diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 8266e899011..80289ca08c3 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -308,7 +308,7 @@ mod prim_never {} /// /// ```no_run /// // Undefined behaviour -/// unsafe { char::from_u32_unchecked(0x110000) }; +/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; /// ``` /// /// USVs are also the exact set of values that may be encoded in UTF-8. Because diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index d54a21b9f16..779db9fffa8 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -57,17 +57,11 @@ tidy: prepare: $(Q)$(BOOTSTRAP) build --stage 2 nonexistent/path/to/trigger/cargo/metadata -TESTS_IN_2 := \ - tests/ui \ - src/tools/linkchecker - ## MSVC native builders -# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows -ci-subset-1: - $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %) -ci-subset-2: - $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2) +# this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows +ci-msvc: + $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 ## MingW native builders diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index d3cb6b6ed52..19ead2f1b11 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -582,28 +582,16 @@ jobs: # Windows Builders # ###################### - - name: x86_64-msvc-1 + - name: x86_64-msvc env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-subset-1 + SCRIPT: make ci-msvc <<: *job-windows-8c - - name: x86_64-msvc-2 - env: - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-subset-2 - <<: *job-windows-8c - - - name: i686-msvc-1 - env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-subset-1 - <<: *job-windows-8c - - - name: i686-msvc-2 + - name: i686-msvc env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-subset-2 + SCRIPT: make ci-msvc <<: *job-windows-8c - name: x86_64-msvc-cargo diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index b512135d927..12a8b2b8db4 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -7,6 +7,7 @@ - [How to write documentation](how-to-write-documentation.md) - [What to include (and exclude)](write-documentation/what-to-include.md) - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md) + - [Re-exports](write-documentation/re-exports.md) - [Linking to items by name](write-documentation/linking-to-items-by-name.md) - [Documentation tests](write-documentation/documentation-tests.md) - [Rustdoc-specific lints](lints.md) diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md new file mode 100644 index 00000000000..593428b8a70 --- /dev/null +++ b/src/doc/rustdoc/src/write-documentation/re-exports.md @@ -0,0 +1,172 @@ +# Re-exports + +Let's start by explaining what are re-exports. To do so, we will use an example where we are +writing a library (named `lib`) with some types dispatched in sub-modules: + +```rust +pub mod sub_module1 { + pub struct Foo; +} +pub mod sub_module2 { + pub struct AnotherFoo; +} +``` + +Users can import them like this: + +```rust,ignore (inline) +use lib::sub_module1::Foo; +use lib::sub_module2::AnotherFoo; +``` + +But what if you want the types to be available directly at the crate root or if we don't want the +modules to be visible for users? That's where re-exports come in: + +```rust,ignore (inline) +// `sub_module1` and `sub_module2` are not visible outside. +mod sub_module1 { + pub struct Foo; +} +mod sub_module2 { + pub struct AnotherFoo; +} +// We re-export both types: +pub use crate::sub_module1::Foo; +pub use crate::sub_module2::AnotherFoo; +``` + +And now users will be able to do: + +```rust,ignore (inline) +use lib::{Foo, AnotherFoo}; +``` + +And since both `sub_module1` and `sub_module2` are private, users won't be able to import them. + +Now what's interesting is that the generated documentation for this crate will show both `Foo` and +`AnotherFoo` directly at the crate root, meaning they have been inlined. There are a few rules to +know whether or not a re-exported item will be inlined. + +## Inlining rules + +If a public item comes from a private module, it will be inlined: + +```rust,ignore (inline) +mod private_module { + pub struct Public; +} +pub mod public_mod { + // `Public` will inlined here since `private_module` is private. + pub use super::private_module::Public; +} +// `Public` will not be inlined here since `public_mod` is public. +pub use self::public_mod::Public; +``` + +Likewise, if an item inherits `#[doc(hidden)]` from any of its ancestors, it will be inlined: + +```rust,ignore (inline) +#[doc(hidden)] +pub mod public_mod { + pub struct Public; +} +// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`. +pub use self::public_mod::Public; +``` + +If an item has `#[doc(hidden)]`, it won't be inlined (nor visible in the generated documentation): + +```rust,ignore (inline) +// This struct won't be visible. +#[doc(hidden)] +pub struct Hidden; + +// This re-export won't be visible. +pub use self::Hidden as InlinedHidden; +``` + +The same applies on re-exports themselves: if you have multiple re-exports and some of them have +`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation: + +```rust,ignore (inline) +mod private_mod { + /// First + pub struct InPrivate; +} + +/// Second +#[doc(hidden)] +pub use self::private_mod::InPrivate as Hidden; +/// Third +pub use self::Hidden as Visible; +``` + +In this case, `InPrivate` will be inlined as `Visible`. However, its documentation will be +`First Third` and not `First Second Third` because the re-export with `Second` as documentation has +`#[doc(hidden)]`, therefore, all its attributes are ignored. + +## Inlining with `#[doc(inline)]` + +You can use the `#[doc(inline)]` attribute if you want to force an item to be inlined: + +```rust,ignore (inline) +pub mod public_mod { + pub struct Public; +} +#[doc(inline)] +pub use self::public_mod::Public; +``` + +With this code, even though `public_mod::Public` is public and present in the documentation, the +`Public` type will be present both at the crate root and in the `public_mod` module. + +## Preventing inlining with `#[doc(no_inline)]` + +On the opposite of the `#[doc(inline)]` attribute, if you want to prevent an item from being +inlined, you can use `#[doc(no_inline)]`: + +```rust,ignore (inline) +mod private_mod { + pub struct Public; +} +#[doc(no_inline)] +pub use self::private_mod::Public; +``` + +In the generated documentation, you will see a re-export at the crate root and not the type +directly. + +## Attributes + +When an item is inlined, its doc comments and most of its attributes will be inlined along with it: + +```rust,ignore (inline) +mod private_mod { + /// First + #[cfg(a)] + pub struct InPrivate; + /// Second + #[cfg(b)] + pub use self::InPrivate as Second; +} + +/// Third +#[doc(inline)] +#[cfg(c)] +pub use self::private_mod::Second as Visible; +``` + +In this case, `Visible` will have as documentation `First Second Third` and will also have as `cfg`: +`#[cfg(a, b, c)]`. + +[Intra-doc links](./linking-to-items-by-name.md) are resolved relative to where the doc comment is +defined. + +There are a few attributes which are not inlined though: + * `#[doc(alias="")]` + * `#[doc(inline)]` + * `#[doc(no_inline)]` + * `#[doc(hidden)]` (because the re-export itself and its attributes are ignored). + +All other attributes are inherited when inlined, so that the documentation matches the behavior if +the inlined item was directly defined at the spot where it's shown. diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 8ecf05f0e12..046d018543f 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -223,12 +223,18 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will not eagerly inline it as a module unless you add `#[doc(inline)]`. +If you want to know more about inlining rules, take a look at the +[`re-exports` chapter](./re-exports.md). + ### `hidden` <span id="dochidden"></span> Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless -the `strip-hidden` pass is removed. +the `strip-hidden` pass is removed. Re-exported items where one of its ancestors has +`#[doc(hidden)]` will be considered the same as private. + +You can find more information in the [`re-exports` chapter](./re-exports.md). ### `alias` diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed index 575dadde906..ac55ab5a8e2 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -2,6 +2,7 @@ #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] +#![allow(unused_must_use)] unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = &*p; @@ -38,7 +39,7 @@ fn _issue1231() { type Bar<'a> = &'a u8; let raw = 42 as *const i32; - unsafe { &*(raw as *const u8) }; + let _ = unsafe { &*(raw as *const u8) }; } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs index 4238ff80478..901a3e90dbe 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -2,6 +2,7 @@ #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] +#![allow(unused_must_use)] unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = std::mem::transmute(p); @@ -38,7 +39,7 @@ fn _issue1231() { type Bar<'a> = &'a u8; let raw = 42 as *const i32; - unsafe { std::mem::transmute::<_, Bar>(raw) }; + let _ = unsafe { std::mem::transmute::<_, Bar>(raw) }; } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr index b3e6c09d2d7..68007edc410 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:7:17 + --> $DIR/transmute_ptr_to_ref.rs:8:17 | LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` @@ -7,127 +7,127 @@ LL | let _: &T = std::mem::transmute(p); = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:10:21 + --> $DIR/transmute_ptr_to_ref.rs:11:21 | LL | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:13:17 + --> $DIR/transmute_ptr_to_ref.rs:14:17 | LL | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:16:21 + --> $DIR/transmute_ptr_to_ref.rs:17:21 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:19:17 + --> $DIR/transmute_ptr_to_ref.rs:20:17 | LL | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:22:21 + --> $DIR/transmute_ptr_to_ref.rs:23:21 | LL | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:25:17 + --> $DIR/transmute_ptr_to_ref.rs:26:17 | LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`) - --> $DIR/transmute_ptr_to_ref.rs:35:32 + --> $DIR/transmute_ptr_to_ref.rs:36:32 | LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`) - --> $DIR/transmute_ptr_to_ref.rs:37:33 + --> $DIR/transmute_ptr_to_ref.rs:38:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> $DIR/transmute_ptr_to_ref.rs:41:14 + --> $DIR/transmute_ptr_to_ref.rs:42:22 | -LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` +LL | let _ = unsafe { std::mem::transmute::<_, Bar>(raw) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:46:14 + --> $DIR/transmute_ptr_to_ref.rs:47:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:47:14 + --> $DIR/transmute_ptr_to_ref.rs:48:14 | LL | 1 => std::mem::transmute(y), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:48:14 + --> $DIR/transmute_ptr_to_ref.rs:49:14 | LL | 2 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:49:14 + --> $DIR/transmute_ptr_to_ref.rs:50:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(y), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:57:19 + --> $DIR/transmute_ptr_to_ref.rs:58:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:58:19 + --> $DIR/transmute_ptr_to_ref.rs:59:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:60:14 + --> $DIR/transmute_ptr_to_ref.rs:61:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:61:14 + --> $DIR/transmute_ptr_to_ref.rs:62:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:69:19 + --> $DIR/transmute_ptr_to_ref.rs:70:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:70:19 + --> $DIR/transmute_ptr_to_ref.rs:71:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:72:14 + --> $DIR/transmute_ptr_to_ref.rs:73:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:73:14 + --> $DIR/transmute_ptr_to_ref.rs:74:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs index 03113585d14..366930a831c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer + let _ = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer } fn main() { diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 2ba8116cadc..6c41add60ef 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | -LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +LL | let _ = unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs index e606d8b283c..59781f02366 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -2,6 +2,6 @@ #[allow(deprecated, invalid_value)] fn main() { - unsafe { std::mem::uninitialized::<!>() }; + let _ = unsafe { std::mem::uninitialized::<!>() }; //~^ ERROR: attempted to instantiate uninhabited type `!` } diff --git a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr index 150128ba2a4..f2cc3430326 100644 --- a/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr +++ b/src/tools/miri/tests/fail/intrinsics/uninit_uninhabited_type.stderr @@ -1,8 +1,8 @@ error: abnormal termination: aborted execution: attempted to instantiate uninhabited type `!` --> $DIR/uninit_uninhabited_type.rs:LL:CC | -LL | unsafe { std::mem::uninitialized::<!>() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` +LL | let _ = unsafe { std::mem::uninitialized::<!>() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` | = note: inside `main` at $DIR/uninit_uninhabited_type.rs:LL:CC diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs index 6d9ae14c5c4..e9c6e464e88 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,5 +1,5 @@ #[allow(deprecated, invalid_value)] fn main() { - unsafe { std::mem::zeroed::<fn()>() }; + let _ = unsafe { std::mem::zeroed::<fn()>() }; //~^ ERROR: attempted to zero-initialize type `fn()`, which is invalid } diff --git a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr index 9d44ba9f746..77d58228043 100644 --- a/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/zero_fn_ptr.stderr @@ -1,8 +1,8 @@ error: abnormal termination: aborted execution: attempted to zero-initialize type `fn()`, which is invalid --> $DIR/zero_fn_ptr.rs:LL:CC | -LL | unsafe { std::mem::zeroed::<fn()>() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid +LL | let _ = unsafe { std::mem::zeroed::<fn()>() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid | = note: inside `main` at $DIR/zero_fn_ptr.rs:LL:CC diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 3f60a90f87a..dc902f8cb02 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -14,13 +14,19 @@ fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> if global { command.arg("--global"); } - let lines = command - .output() - .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) - .unwrap_or(String::new()); + let lines = match command.output() { + Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(), + Err(e) => { + eprintln!( + "path to npm can be wrong, provided path: {npm:?}. Try to set npm path \ + in config.toml in [build.npm]", + ); + panic!("{:?}", e) + } + }; lines .lines() - .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) + .find_map(|l| l.rsplit(':').next()?.strip_prefix("browser-ui-test@")) .map(|v| v.to_owned()) } diff --git a/tests/codegen/slice-iter-fold.rs b/tests/codegen/slice-iter-fold.rs new file mode 100644 index 00000000000..9391c176130 --- /dev/null +++ b/tests/codegen/slice-iter-fold.rs @@ -0,0 +1,14 @@ +// ignore-debug: the debug assertions get in the way +// compile-flags: -O +// min-llvm-version: 16 +#![crate_type = "lib"] + +// CHECK-LABEL: @slice_fold_to_last +#[no_mangle] +pub fn slice_fold_to_last(slice: &[i32]) -> Option<&i32> { + // CHECK-NOT: loop + // CHECK-NOT: br + // CHECK-NOT: call + // CHECK: ret + slice.iter().fold(None, |_, i| Some(i)) +} diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs index 606d68ff3ab..14fef4e2cd5 100644 --- a/tests/codegen/vec-shrink-panik.rs +++ b/tests/codegen/vec-shrink-panik.rs @@ -38,14 +38,6 @@ pub fn issue71861(vec: Vec<u32>) -> Box<[u32]> { #[no_mangle] pub fn issue75636<'a>(iter: &[&'a str]) -> Box<[&'a str]> { // CHECK-NOT: panic - - // Call to panic_cannot_unwind in case of double-panic is expected, - // on LLVM 16 and older, but other panics are not. - // old: filter - // old-NEXT: ; call core::panicking::panic_cannot_unwind - // old-NEXT: panic_cannot_unwind - - // CHECK-NOT: panic iter.iter().copied().collect() } diff --git a/tests/run-make/panic-abort-eh_frame/Makefile b/tests/run-make/panic-abort-eh_frame/Makefile new file mode 100644 index 00000000000..1cb7bf575cb --- /dev/null +++ b/tests/run-make/panic-abort-eh_frame/Makefile @@ -0,0 +1,10 @@ +# only-linux +# +# This test ensures that `panic=abort` code (without `C-unwind`, that is) should not have any +# unwinding related `.eh_frame` sections emitted. + +include ../tools.mk + +all: + $(RUSTC) foo.rs --crate-type=lib --emit=obj=$(TMPDIR)/foo.o -Cpanic=abort + objdump --dwarf=frames $(TMPDIR)/foo.o | $(CGREP) -v 'DW_CFA' diff --git a/tests/run-make/panic-abort-eh_frame/foo.rs b/tests/run-make/panic-abort-eh_frame/foo.rs new file mode 100644 index 00000000000..e1853529455 --- /dev/null +++ b/tests/run-make/panic-abort-eh_frame/foo.rs @@ -0,0 +1,10 @@ +#![no_std] + +#[panic_handler] +fn handler(_: &core::panic::PanicInfo<'_>) -> ! { + loop {} +} + +pub unsafe fn oops(x: *const u32) -> u32 { + *x +} diff --git a/tests/rustdoc/issue-109449-doc-hidden-reexports.rs b/tests/rustdoc/issue-109449-doc-hidden-reexports.rs new file mode 100644 index 00000000000..b0c22540180 --- /dev/null +++ b/tests/rustdoc/issue-109449-doc-hidden-reexports.rs @@ -0,0 +1,143 @@ +// Test to enforce rules over re-exports inlining from +// <https://github.com/rust-lang/rust/issues/109449>. + +#![crate_name = "foo"] + +mod private_module { + #[doc(hidden)] + pub struct Public; + #[doc(hidden)] + pub type Bar = (); +} + +#[doc(hidden)] +mod module { + pub struct Public2; + pub type Bar2 = (); +} + +#[doc(hidden)] +pub type Bar3 = (); +#[doc(hidden)] +pub struct FooFoo; + +// Checking that re-exporting a `#[doc(hidden)]` item will NOT inline it. +pub mod single_reexport { + // @has 'foo/single_reexport/index.html' + + // First we check that we have 4 type aliases. + // @count - '//*[@id="main-content"]/*[@class="item-table"]//code' 4 + + // Then we check that we have the correct link for each re-export. + + // @!has - '//*[@href="struct.Foo.html"]' 'Foo' + // @has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' + pub use crate::private_module::Public as Foo; + // @!has - '//*[@href="type.Foo2.html"]' 'Foo2' + // @has - '//*[@id="reexport.Foo2"]/code' 'pub use crate::private_module::Bar as Foo2;' + pub use crate::private_module::Bar as Foo2; + // @!has - '//*[@href="type.Yo.html"]' 'Yo' + // @has - '//*[@id="reexport.Yo"]/code' 'pub use crate::Bar3 as Yo;' + pub use crate::Bar3 as Yo; + // @!has - '//*[@href="struct.Yo2.html"]' 'Yo2' + // @has - '//*[@id="reexport.Yo2"]/code' 'pub use crate::FooFoo as Yo2;' + pub use crate::FooFoo as Yo2; + + // Checking that each file is also created as expected. + // @!has 'foo/single_reexport/struct.Foo.html' + // @!has 'foo/single_reexport/type.Foo2.html' + // @!has 'foo/single_reexport/type.Yo.html' + // @!has 'foo/single_reexport/struct.Yo2.html' +} + +// However, re-exporting an item inheriting `#[doc(hidden)]` will inline it. +pub mod single_reexport_inherit_hidden { + // @has 'foo/single_reexport_inherit_hidden/index.html' + + // @has - '//*[@href="struct.Foo3.html"]' 'Foo3' + pub use crate::module::Public2 as Foo3; + // @has - '//*[@href="type.Foo4.html"]' 'Foo4' + pub use crate::module::Bar2 as Foo4; + + // @has 'foo/single_reexport_inherit_hidden/struct.Foo3.html' + // @has 'foo/single_reexport_inherit_hidden/type.Foo4.html' +} + +pub mod single_reexport_no_inline { + // First we ensure that we only have re-exports and no inlined items. + // @has 'foo/single_reexport_no_inline/index.html' + // @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 1 + // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Re-exports' + + // Now we check that we don't have links to the items, just `pub use`. + // @has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Public as XFoo;' + // @!has - '//*[@id="main-content"]//a' 'XFoo' + #[doc(no_inline)] + pub use crate::private_module::Public as XFoo; + // @has - '//*[@id="main-content"]//*' 'pub use crate::private_module::Bar as Foo2;' + // @!has - '//*[@id="main-content"]//a' 'Foo2' + #[doc(no_inline)] + pub use crate::private_module::Bar as Foo2; + // @has - '//*[@id="main-content"]//*' 'pub use crate::Bar3 as Yo;' + // @!has - '//*[@id="main-content"]//a' 'Yo' + #[doc(no_inline)] + pub use crate::Bar3 as Yo; + // @has - '//*[@id="main-content"]//*' 'pub use crate::FooFoo as Yo2;' + // @!has - '//*[@id="main-content"]//a' 'Yo2' + #[doc(no_inline)] + pub use crate::FooFoo as Yo2; + // @has - '//*[@id="main-content"]//*' 'pub use crate::module::Public2 as Foo3;' + // @!has - '//*[@id="main-content"]//a' 'Foo3' + #[doc(no_inline)] + pub use crate::module::Public2 as Foo3; + // @has - '//*[@id="main-content"]//*' 'pub use crate::module::Bar2 as Foo4;' + // @!has - '//*[@id="main-content"]//a' 'Foo4' + #[doc(no_inline)] + pub use crate::module::Bar2 as Foo4; +} + +// Checking that glob re-exports don't inline `#[doc(hidden)]` items. +pub mod glob_reexport { + // With glob re-exports, we don't inline `#[doc(hidden)]` items so only `module` items + // should be inlined. + // @has 'foo/glob_reexport/index.html' + // @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 3 + // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Re-exports' + // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs' + // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Type Definitions' + + // Now we check we have 1 re-export and 2 inlined items. + // If not item from a glob re-export is visible, we don't show the re-export. + // @!has - '//*[@id="main-content"]//*' 'pub use crate::private_module::*;' + pub use crate::private_module::*; + // @has - '//*[@id="main-content"]//*' 'pub use crate::*;' + pub use crate::*; + // This one should be inlined. + // @!has - '//*[@id="main-content"]//*' 'pub use crate::module::*;' + // @has - '//*[@id="main-content"]//a[@href="struct.Public2.html"]' 'Public2' + // @has - '//*[@id="main-content"]//a[@href="type.Bar2.html"]' 'Bar2' + // And we check that the two files were created too. + // @has 'foo/glob_reexport/struct.Public2.html' + // @has 'foo/glob_reexport/type.Bar2.html' + pub use crate::module::*; +} + +mod private { + /// Original. + pub struct Bar3; +} + +// Checking that `#[doc(hidden)]` re-exports documentation isn't generated. +pub mod doc_hidden_reexport { + // @has 'foo/doc_hidden_reexport/index.html' + // Ensure there is only one item in this page and that it's a struct. + // @count - '//*[@class="item-name"]' 1 + // @has - '//a[@class="struct"]' 'Reexport' + // Check that the `#[doc(hidden)]` re-export's attributes are not taken into account. + // @has - '//*[@class="desc docblock-short"]' 'Visible. Original.' + /// Hidden. + #[doc(hidden)] + pub use crate::private::Bar3; + /// Visible. + pub use self::Bar3 as Reexport; +} diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/issues/issue-1460.stderr index eb7661fad56..d4a8c8955e2 100644 --- a/tests/ui/issues/issue-1460.stderr +++ b/tests/ui/issues/issue-1460.stderr @@ -1,8 +1,8 @@ warning: unused closure that must be used - --> $DIR/issue-1460.rs:6:5 + --> $DIR/issue-1460.rs:6:6 | LL | {|i: u32| if 1 == i { }}; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: closures are lazy and do nothing unless called = note: `#[warn(unused_must_use)]` on by default diff --git a/tests/ui/lint/issue-112489.rs b/tests/ui/lint/issue-112489.rs new file mode 100644 index 00000000000..559edf0e4f2 --- /dev/null +++ b/tests/ui/lint/issue-112489.rs @@ -0,0 +1,17 @@ +// check-pass +use std::borrow::Borrow; + +struct S; + +trait T: Sized { + fn foo(self) {} +} + +impl T for S {} +impl T for &S {} + +fn main() { + let s = S; + s.borrow().foo(); + s.foo(); +} diff --git a/tests/ui/lint/type-overflow.stderr b/tests/ui/lint/type-overflow.stderr index 62cb1f7f4aa..e7c90dcc81b 100644 --- a/tests/ui/lint/type-overflow.stderr +++ b/tests/ui/lint/type-overflow.stderr @@ -16,17 +16,33 @@ warning: literal out of range for `i8` --> $DIR/type-overflow.rs:10:16 | LL | let fail = 0b1000_0001i8; - | ^^^^^^^^^^^^^ help: consider using the type `u8` instead: `0b1000_0001u8` + | ^^^^^^^^^^^^^ | = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into the type `i8` and will become `-127i8` +help: consider using the type `u8` instead + | +LL | let fail = 0b1000_0001u8; + | ~~~~~~~~~~~~~ +help: to use as a negative number (decimal `-127`), consider using the type `u8` for the literal and cast it to `i8` + | +LL | let fail = 0b1000_0001u8 as i8; + | ~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `i64` --> $DIR/type-overflow.rs:12:16 | LL | let fail = 0x8000_0000_0000_0000i64; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the type `u64` instead: `0x8000_0000_0000_0000u64` + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into the type `i64` and will become `-9223372036854775808i64` +help: consider using the type `u64` instead + | +LL | let fail = 0x8000_0000_0000_0000u64; + | ~~~~~~~~~~~~~~~~~~~~~~~~ +help: to use as a negative number (decimal `-9223372036854775808`), consider using the type `u64` for the literal and cast it to `i64` + | +LL | let fail = 0x8000_0000_0000_0000u64 as i64; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `u32` --> $DIR/type-overflow.rs:14:16 @@ -44,6 +60,10 @@ LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000; | = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into the type `i128` and will become `-170141183460469231731687303715884105728i128` = help: consider using the type `u128` instead +help: to use as a negative number (decimal `-170141183460469231731687303715884105728`), consider using the type `u128` for the literal and cast it to `i128` + | +LL | let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000u128 as i128; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `i32` --> $DIR/type-overflow.rs:19:16 @@ -53,6 +73,10 @@ LL | let fail = 0x8FFF_FFFF_FFFF_FFFE; | = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into the type `i32` and will become `-2i32` = help: consider using the type `i128` instead +help: to use as a negative number (decimal `-2`), consider using the type `u32` for the literal and cast it to `i32` + | +LL | let fail = 0x8FFF_FFFF_FFFF_FFFEu32 as i32; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ warning: literal out of range for `i8` --> $DIR/type-overflow.rs:21:17 diff --git a/tests/ui/lint/unused/must-use-block-expr.fixed b/tests/ui/lint/unused/must-use-block-expr.fixed new file mode 100644 index 00000000000..642012812bd --- /dev/null +++ b/tests/ui/lint/unused/must-use-block-expr.fixed @@ -0,0 +1,36 @@ +// run-rustfix +// check-pass + +#![warn(unused_must_use)] + +#[must_use] +fn foo() -> i32 { + 42 +} + +fn bar() { + { + let _ = foo(); + //~^ WARN unused return value + } +} + +fn baz() { + { + let _ = foo(); + //~^ WARN unused return value + }; +} + +fn main() { + bar(); + baz(); + { + let _ = 1 + 2; + //~^ WARN unused arithmetic operation + } + { + let _ = 1 + 2; + //~^ WARN unused arithmetic operation + }; +} diff --git a/tests/ui/lint/unused/must-use-block-expr.rs b/tests/ui/lint/unused/must-use-block-expr.rs new file mode 100644 index 00000000000..e0a680aa07d --- /dev/null +++ b/tests/ui/lint/unused/must-use-block-expr.rs @@ -0,0 +1,36 @@ +// run-rustfix +// check-pass + +#![warn(unused_must_use)] + +#[must_use] +fn foo() -> i32 { + 42 +} + +fn bar() { + { + foo(); + //~^ WARN unused return value + } +} + +fn baz() { + { + foo() + //~^ WARN unused return value + }; +} + +fn main() { + bar(); + baz(); + { + 1 + 2; + //~^ WARN unused arithmetic operation + } + { + 1 + 2 + //~^ WARN unused arithmetic operation + }; +} diff --git a/tests/ui/lint/unused/must-use-block-expr.stderr b/tests/ui/lint/unused/must-use-block-expr.stderr new file mode 100644 index 00000000000..d821beb1d92 --- /dev/null +++ b/tests/ui/lint/unused/must-use-block-expr.stderr @@ -0,0 +1,51 @@ +warning: unused return value of `foo` that must be used + --> $DIR/must-use-block-expr.rs:13:9 + | +LL | foo(); + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/must-use-block-expr.rs:4:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo(); + | +++++++ + +warning: unused return value of `foo` that must be used + --> $DIR/must-use-block-expr.rs:20:9 + | +LL | foo() + | ^^^^^ + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = foo(); + | +++++++ + + +warning: unused arithmetic operation that must be used + --> $DIR/must-use-block-expr.rs:29:9 + | +LL | 1 + 2; + | ^^^^^ the arithmetic operation produces a value + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = 1 + 2; + | +++++++ + +warning: unused arithmetic operation that must be used + --> $DIR/must-use-block-expr.rs:33:9 + | +LL | 1 + 2 + | ^^^^^ the arithmetic operation produces a value + | +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = 1 + 2; + | +++++++ + + +warning: 4 warnings emitted + diff --git a/tests/ui/match/issue-112438.rs b/tests/ui/match/issue-112438.rs new file mode 100644 index 00000000000..15f380f7fb4 --- /dev/null +++ b/tests/ui/match/issue-112438.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(inline_const_pat)] +#![allow(dead_code)] +#![allow(incomplete_features)] +fn foo<const V: usize>() { + match 0 { + const { 1 << 5 } | _ => {} + } +} + +fn main() {} diff --git a/tests/ui/resolve/issue-112472-multi-generics-suggestion.fixed b/tests/ui/resolve/issue-112472-multi-generics-suggestion.fixed new file mode 100644 index 00000000000..892697493b7 --- /dev/null +++ b/tests/ui/resolve/issue-112472-multi-generics-suggestion.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +use std::fmt::Debug; +use std::marker::PhantomData; +use std::convert::{self, TryFrom}; + +#[allow(unused)] +struct Codec<EncodeLine, DecodeLine> { + phantom_decode: PhantomData<DecodeLine>, + phantom_encode: PhantomData<EncodeLine>, +} + +pub enum ParseError {} + +impl<EncodeLine, DecodeLine> Codec<EncodeLine, DecodeLine> where + DecodeLine: Debug + convert::TryFrom<String>, + DecodeLine: convert::TryFrom<String, Error = ParseError>, + //~^ ERROR expected trait, found enum `ParseError` + //~| HELP constrain the associated type to `ParseError` +{ +} + +impl<EncodeLine, DecodeLine> Codec<EncodeLine, DecodeLine> where + DecodeLine: Debug + TryFrom<String>, + DecodeLine: TryFrom<String, Error = ParseError>, + //~^ ERROR expected trait, found enum `ParseError` + //~| HELP constrain the associated type to `ParseError` +{ +} + +fn main() {} diff --git a/tests/ui/resolve/issue-112472-multi-generics-suggestion.rs b/tests/ui/resolve/issue-112472-multi-generics-suggestion.rs new file mode 100644 index 00000000000..2b2f5f1ad8d --- /dev/null +++ b/tests/ui/resolve/issue-112472-multi-generics-suggestion.rs @@ -0,0 +1,31 @@ +// run-rustfix + +use std::fmt::Debug; +use std::marker::PhantomData; +use std::convert::{self, TryFrom}; + +#[allow(unused)] +struct Codec<EncodeLine, DecodeLine> { + phantom_decode: PhantomData<DecodeLine>, + phantom_encode: PhantomData<EncodeLine>, +} + +pub enum ParseError {} + +impl<EncodeLine, DecodeLine> Codec<EncodeLine, DecodeLine> where + DecodeLine: Debug + convert::TryFrom<String>, + <DecodeLine as convert::TryFrom<String>>::Error: ParseError, + //~^ ERROR expected trait, found enum `ParseError` + //~| HELP constrain the associated type to `ParseError` +{ +} + +impl<EncodeLine, DecodeLine> Codec<EncodeLine, DecodeLine> where + DecodeLine: Debug + TryFrom<String>, + <DecodeLine as TryFrom<String>>::Error: ParseError, + //~^ ERROR expected trait, found enum `ParseError` + //~| HELP constrain the associated type to `ParseError` +{ +} + +fn main() {} diff --git a/tests/ui/resolve/issue-112472-multi-generics-suggestion.stderr b/tests/ui/resolve/issue-112472-multi-generics-suggestion.stderr new file mode 100644 index 00000000000..f463e2dad2c --- /dev/null +++ b/tests/ui/resolve/issue-112472-multi-generics-suggestion.stderr @@ -0,0 +1,25 @@ +error[E0404]: expected trait, found enum `ParseError` + --> $DIR/issue-112472-multi-generics-suggestion.rs:17:54 + | +LL | <DecodeLine as convert::TryFrom<String>>::Error: ParseError, + | ^^^^^^^^^^ not a trait + | +help: constrain the associated type to `ParseError` + | +LL | DecodeLine: convert::TryFrom<String, Error = ParseError>, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0404]: expected trait, found enum `ParseError` + --> $DIR/issue-112472-multi-generics-suggestion.rs:25:45 + | +LL | <DecodeLine as TryFrom<String>>::Error: ParseError, + | ^^^^^^^^^^ not a trait + | +help: constrain the associated type to `ParseError` + | +LL | DecodeLine: TryFrom<String, Error = ParseError>, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0404`. |
