diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 307e22b0df1fd..b40066d05d355 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -4,3 +4,5 @@ a06baa56b95674fc626b3c3fd680d6a65357fe60 95e00bfed801e264e9c4ac817004153ca0f19eb6 # reformat with new rustfmt 971c549ca334b7b7406e61e958efcca9c4152822 +# refactor infcx building +283abbf0e7d20176f76006825b5c52e9a4234e4c diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 8ad40c0aa0a5d..7457369aa58cb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,6 +1,4 @@ -use rustc_errors::{ - Applicability, Diagnostic, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, -}; +use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; @@ -629,25 +627,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.buffer_error(err); } - fn suggest_map_index_mut_alternatives( - &self, - ty: Ty<'_>, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - span: Span, - ) { + fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) { let Some(adt) = ty.ty_adt_def() else { return }; let did = adt.did(); if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did) || self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did) { - struct V<'a, 'b, 'tcx, G: EmissionGuarantee> { + struct V<'a, 'tcx> { assign_span: Span, - err: &'a mut DiagnosticBuilder<'b, G>, + err: &'a mut Diagnostic, ty: Ty<'tcx>, suggested: bool, } - impl<'a, 'b: 'a, 'hir, 'tcx, G: EmissionGuarantee> Visitor<'hir> for V<'a, 'b, 'tcx, G> { - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'hir>) { + impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { hir::intravisit::walk_stmt(self, stmt); let expr = match stmt.kind { hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr, @@ -705,7 +698,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), (rv.span.shrink_to_hi(), ")".to_string()), ], - ].into_iter(), + ], Applicability::MachineApplicable, ); self.suggested = true; diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 18b3408b06ab4..fa975ff2c20cf 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -171,3 +171,4 @@ infer_msl_introduces_static = introduces a `'static` lifetime requirement infer_msl_unmet_req = because this has an unmet lifetime requirement infer_msl_trait_note = this has an implicit `'static` lifetime requirement infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement +infer_suggest_add_let_for_letchains = consider adding `let` diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 455ff34f7247f..6d42b23fb3a21 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -125,6 +125,9 @@ parser_if_expression_missing_condition = missing condition for `if` expression parser_expected_expression_found_let = expected expression, found `let` statement +parser_expect_eq_instead_of_eqeq = expected `=`, found `==` + .suggestion = consider using `=` here + parser_expected_else_block = expected `{"{"}`, found {$first_tok} .label = expected an `if` or a block after this `else` .suggestion = add an `if` if this is the condition of a chained `else if` statement diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 43101bbb9d31c..375e3ebd77df7 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -742,7 +742,7 @@ impl Diagnostic { &mut self, sp: Span, msg: impl Into, - suggestions: impl Iterator, + suggestions: impl IntoIterator, applicability: Applicability, ) -> &mut Self { self.span_suggestions_with_style( @@ -759,11 +759,11 @@ impl Diagnostic { &mut self, sp: Span, msg: impl Into, - suggestions: impl Iterator, + suggestions: impl IntoIterator, applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { - let mut suggestions: Vec<_> = suggestions.collect(); + let mut suggestions: Vec<_> = suggestions.into_iter().collect(); suggestions.sort(); debug_assert!( @@ -790,10 +790,10 @@ impl Diagnostic { pub fn multipart_suggestions( &mut self, msg: impl Into, - suggestions: impl Iterator>, + suggestions: impl IntoIterator>, applicability: Applicability, ) -> &mut Self { - let suggestions: Vec<_> = suggestions.collect(); + let suggestions: Vec<_> = suggestions.into_iter().collect(); debug_assert!( !(suggestions .iter() diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 730061fca9936..18cbf963494fc 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -599,13 +599,13 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { &mut self, sp: Span, msg: impl Into, - suggestions: impl Iterator, + suggestions: impl IntoIterator, applicability: Applicability, ) -> &mut Self); forward!(pub fn multipart_suggestions( &mut self, msg: impl Into, - suggestions: impl Iterator>, + suggestions: impl IntoIterator>, applicability: Applicability, ) -> &mut Self); forward!(pub fn span_suggestion_short( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 50e2b0f89267d..45146a5885b42 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1805,6 +1805,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Str | ty::Projection(_) | ty::Param(_) => format!("{deref_ty}"), + // we need to test something like <&[_]>::len + // and Vec::function(); + // <&[_]>::len doesn't need an extra "<>" between + // but for Adt type like Vec::function() + // we would suggest <[_]>::function(); + _ if self.tcx.sess.source_map().span_wrapped_by_angle_bracket(ty.span) => format!("{deref_ty}"), _ => format!("<{deref_ty}>"), }; err.span_suggestion_verbose( diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index bb04e1c49baea..ec4eeb8caa27c 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -180,6 +180,18 @@ pub enum SourceKindMultiSuggestion<'a> { }, } +#[derive(Subdiagnostic)] +#[suggestion( + infer_suggest_add_let_for_letchains, + style = "verbose", + applicability = "machine-applicable", + code = "let " +)] +pub(crate) struct SuggAddLetForLetChains { + #[primary_span] + pub span: Span, +} + impl<'a> SourceKindMultiSuggestion<'a> { pub fn new_fully_qualified( span: Span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 61519454a2cf5..22f32251f6df0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Error Reporting Code for the inference engine //! //! Because of the way inference, and in particular region inference, @@ -58,12 +59,15 @@ use crate::traits::{ StatementAsExpression, }; +use crate::errors::SuggAddLetForLetChains; +use hir::intravisit::{walk_expr, walk_stmt}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::Node; use rustc_middle::dep_graph::DepContext; @@ -2336,6 +2340,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } } + // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, + // we try to suggest to add the missing `let` for `if let Some(..) = expr` + (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { + self.suggest_let_for_letchains(&mut err, &trace.cause, span); + } _ => {} } } @@ -2360,6 +2369,67 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { diag } + /// Try to find code with pattern `if Some(..) = expr` + /// use a `visitor` to mark the `if` which its span contains given error span, + /// and then try to find a assignment in the `cond` part, which span is equal with error span + fn suggest_let_for_letchains( + &self, + err: &mut Diagnostic, + cause: &ObligationCause<'_>, + span: Span, + ) { + let hir = self.tcx.hir(); + let fn_hir_id = hir.get_parent_node(cause.body_id); + if let Some(node) = self.tcx.hir().find(fn_hir_id) && + let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn(_sig, _, body_id), .. + }) = node { + let body = hir.body(*body_id); + + /// Find the if expression with given span + struct IfVisitor { + pub result: bool, + pub found_if: bool, + pub err_span: Span, + } + + impl<'v> Visitor<'v> for IfVisitor { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if self.result { return; } + match ex.kind { + hir::ExprKind::If(cond, _, _) => { + self.found_if = true; + walk_expr(self, cond); + self.found_if = false; + } + _ => walk_expr(self, ex), + } + } + + fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { + if let hir::StmtKind::Local(hir::Local { + span, pat: hir::Pat{..}, ty: None, init: Some(_), .. + }) = &ex.kind + && self.found_if + && span.eq(&self.err_span) { + self.result = true; + } + walk_stmt(self, ex); + } + + fn visit_body(&mut self, body: &'v hir::Body<'v>) { + hir::intravisit::walk_body(self, body); + } + } + + let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; + visitor.visit_body(&body); + if visitor.result { + err.subdiagnostic(SuggAddLetForLetChains{span: span.shrink_to_lo()}); + } + } + } + fn emit_tuple_wrap_err( &self, err: &mut Diagnostic, diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0660e9b79a700..c1d9f496c5b22 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -506,6 +506,9 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &'tcx ty::List { } } +/// Similar to [`Binder`] except that it tracks early bound generics, i.e. `struct Foo(T)` +/// needs `T` substituted immediately. This type primarily exists to avoid forgetting to call +/// `subst`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable)] pub struct EarlyBinder(pub T); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0924c8537159c..e3acc11811f42 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -420,6 +420,15 @@ pub(crate) struct ExpectedExpressionFoundLet { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parser_expect_eq_instead_of_eqeq)] +pub(crate) struct ExpectedEqForLetExpr { + #[primary_span] + pub span: Span, + #[suggestion(applicability = "maybe-incorrect", code = "=", style = "verbose")] + pub sugg_span: Span, +} + #[derive(Diagnostic)] #[diag(parser_expected_else_block)] pub(crate) struct ExpectedElseBlock { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d784fef2bed58..da2d20e47ee68 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -9,9 +9,9 @@ use crate::errors::{ ArrayBracketsInsteadOfSpaces, ArrayBracketsInsteadOfSpacesSugg, AsyncMoveOrderIncorrect, BinaryFloatLiteralNotSupported, BracesForStructLiteral, CatchAfterTry, CommaAfterBaseStruct, ComparisonInterpretedAsGeneric, ComparisonOrShiftInterpretedAsGenericSugg, - DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedExpressionFoundLet, - FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, FoundExprWouldBeStmt, - HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition, + DoCatchSyntaxRemoved, DotDotDot, EqFieldInit, ExpectedElseBlock, ExpectedEqForLetExpr, + ExpectedExpressionFoundLet, FieldExpressionWithGeneric, FloatLiteralRequiresIntegerPart, + FoundExprWouldBeStmt, HexadecimalFloatLiteralNotSupported, IfExpressionMissingCondition, IfExpressionMissingThenBlock, IfExpressionMissingThenBlockSub, IntLiteralTooLarge, InvalidBlockMacroSegment, InvalidComparisonOperator, InvalidComparisonOperatorSub, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth, @@ -2329,7 +2329,15 @@ impl<'a> Parser<'a> { RecoverColon::Yes, CommaRecoveryMode::LikelyTuple, )?; - self.expect(&token::Eq)?; + if self.token == token::EqEq { + self.sess.emit_err(ExpectedEqForLetExpr { + span: self.token.span, + sugg_span: self.token.span, + }); + self.bump(); + } else { + self.expect(&token::Eq)?; + } let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| { this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) })?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bda301c52e960..d657a2891171d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -971,6 +971,23 @@ impl<'a> Parser<'a> { if self.eat(&token::ModSep) { self.parse_use_tree_glob_or_nested()? } else { + // Recover from using a colon as path separator. + while self.eat_noexpect(&token::Colon) { + self.struct_span_err(self.prev_token.span, "expected `::`, found `:`") + .span_suggestion_short( + self.prev_token.span, + "use double colon", + "::", + Applicability::MachineApplicable, + ) + .note_once("import paths are delimited using `::`") + .emit(); + + // We parse the rest of the path and append it to the original prefix. + self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?; + prefix.span = lo.to(self.prev_token.span); + } + UseTreeKind::Simple(self.parse_rename()?, DUMMY_NODE_ID, DUMMY_NODE_ID) } }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 2a8512acf8cfa..3a67c032b3bdd 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -401,7 +401,7 @@ impl<'a> Parser<'a> { .span_suggestions( span.shrink_to_hi(), "add `mut` or `const` here", - ["mut ".to_string(), "const ".to_string()].into_iter(), + ["mut ".to_string(), "const ".to_string()], Applicability::HasPlaceholders, ) .emit(); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index c6fe40f72fc63..c181de48a9ad8 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -87,6 +87,7 @@ use self::VarKind::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; +use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -1690,7 +1691,7 @@ impl<'tcx> Liveness<'_, 'tcx> { &self, name: &str, opt_body: Option<&hir::Body<'_>>, - err: &mut rustc_errors::DiagnosticBuilder<'_, ()>, + err: &mut Diagnostic, ) -> bool { let mut has_litstring = false; let Some(opt_body) = opt_body else {return false;}; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a1338dcd4771b..cdc28db13f3ac 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -437,7 +437,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn try_lookup_name_relaxed( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], span: Span, @@ -497,7 +497,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .contains(span) { // Already reported this issue on the lhs of the type ascription. - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); return (true, candidates); } } @@ -616,7 +616,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn suggest_trait_and_bounds( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, source: PathSource<'_>, res: Option, span: Span, @@ -691,7 +691,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn suggest_typo( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], span: Span, @@ -750,7 +750,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn err_code_special_cases( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, source: PathSource<'_>, path: &[Segment], span: Span, @@ -1941,7 +1941,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, &msg, - suggestable_variants.into_iter(), + suggestable_variants, Applicability::MaybeIncorrect, ); } @@ -1995,7 +1995,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, msg, - suggestable_variants.into_iter(), + suggestable_variants, Applicability::MaybeIncorrect, ); } @@ -2025,7 +2025,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, msg, - suggestable_variants_with_placeholders.into_iter(), + suggestable_variants_with_placeholders, Applicability::HasPlaceholders, ); } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 3baa2e03cbad7..7ea028b12efc4 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -753,6 +753,50 @@ impl SourceMap { } } + /// Given a 'Span', tries to tell if the next character is '>' + /// and the previous charactoer is '<' after skipping white space + /// return true if wrapped by '<>' + pub fn span_wrapped_by_angle_bracket(&self, span: Span) -> bool { + self.span_to_source(span, |src, start_index, end_index| { + if src.get(start_index..end_index).is_none() { + return Ok(false); + } + // test the right side to match '>' after skipping white space + let end_src = &src[end_index..]; + let mut i = 0; + while let Some(cc) = end_src.chars().nth(i) { + if cc == ' ' { + i = i + 1; + } else if cc == '>' { + // found > in the right; + break; + } else { + // failed to find '>' return false immediately + return Ok(false); + } + } + // test the left side to match '<' after skipping white space + i = start_index; + let start_src = &src[0..start_index]; + while let Some(cc) = start_src.chars().nth(i) { + if cc == ' ' { + if i == 0 { + return Ok(false); + } + i = i - 1; + } else if cc == '<' { + // found < in the left + break; + } else { + // failed to find '<' return false immediately + return Ok(false); + } + } + return Ok(true); + }) + .map_or(false, |is_accessible| is_accessible) + } + /// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char` /// `c`. pub fn span_through_char(&self, sp: Span, c: char) -> Span { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1bcb02ecb3053..77d9a0920036a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1911,6 +1911,7 @@ impl Target { Abi::Stdcall { unwind } } Abi::System { unwind } => Abi::C { unwind }, + Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false }, Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false }, Abi::EfiApi => Abi::C { unwind: false }, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index aece4ab792285..540b1fa2b0fb7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1116,7 +1116,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestions( span.shrink_to_lo(), "consider borrowing here", - ["&".to_string(), "&mut ".to_string()].into_iter(), + ["&".to_string(), "&mut ".to_string()], Applicability::MaybeIncorrect, ); } else { diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index aa13435e6808d..c755afa39eb60 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -86,7 +86,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; -use crate::marker; +use crate::intrinsics::const_eval_select; +use crate::marker::{self, Destruct}; #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] @@ -183,6 +184,7 @@ mod sip; /// [impl]: ../../std/primitive.str.html#impl-Hash-for-str #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Hash"] +#[const_trait] pub trait Hash { /// Feeds this value into the given [`Hasher`]. /// @@ -234,13 +236,25 @@ pub trait Hash { /// [`hash`]: Hash::hash /// [`hash_slice`]: Hash::hash_slice #[stable(feature = "hash_slice", since = "1.3.0")] - fn hash_slice(data: &[Self], state: &mut H) + fn hash_slice(data: &[Self], state: &mut H) where Self: Sized, { - for piece in data { - piece.hash(state); + //FIXME(const_trait_impl): revert to only a for loop + fn rt(data: &[T], state: &mut H) { + for piece in data { + piece.hash(state) + } + } + const fn ct(data: &[T], state: &mut H) { + let mut i = 0; + while i < data.len() { + data[i].hash(state); + i += 1; + } } + // SAFETY: same behavior, CT just uses while instead of for + unsafe { const_eval_select((data, state), ct, rt) }; } } @@ -313,6 +327,7 @@ pub use macros::Hash; /// [`write_u8`]: Hasher::write_u8 /// [`write_u32`]: Hasher::write_u32 #[stable(feature = "rust1", since = "1.0.0")] +#[const_trait] pub trait Hasher { /// Returns the hash value for the values written so far. /// @@ -558,7 +573,8 @@ pub trait Hasher { } #[stable(feature = "indirect_hasher_impl", since = "1.22.0")] -impl Hasher for &mut H { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const Hasher for &mut H { fn finish(&self) -> u64 { (**self).finish() } @@ -638,6 +654,7 @@ impl Hasher for &mut H { /// [`build_hasher`]: BuildHasher::build_hasher /// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] +#[const_trait] pub trait BuildHasher { /// Type of the hasher that will be created. #[stable(since = "1.7.0", feature = "build_hasher")] @@ -698,9 +715,10 @@ pub trait BuildHasher { /// ); /// ``` #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")] - fn hash_one(&self, x: T) -> u64 + fn hash_one(&self, x: T) -> u64 where Self: Sized, + Self::Hasher: ~const Hasher + ~const Destruct, { let mut hasher = self.build_hasher(); x.hash(&mut hasher); @@ -764,7 +782,8 @@ impl fmt::Debug for BuildHasherDefault { } #[stable(since = "1.7.0", feature = "build_hasher")] -impl BuildHasher for BuildHasherDefault { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const BuildHasher for BuildHasherDefault { type Hasher = H; fn build_hasher(&self) -> H { @@ -806,14 +825,15 @@ mod impls { macro_rules! impl_write { ($(($ty:ident, $meth:ident),)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for $ty { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for $ty { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { state.$meth(*self) } #[inline] - fn hash_slice(data: &[$ty], state: &mut H) { + fn hash_slice(data: &[$ty], state: &mut H) { let newlen = data.len() * mem::size_of::<$ty>(); let ptr = data.as_ptr() as *const u8; // SAFETY: `ptr` is valid and aligned, as this macro is only used @@ -842,33 +862,37 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for bool { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for bool { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { state.write_u8(*self as u8) } } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for char { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for char { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { state.write_u32(*self as u32) } } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for str { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for str { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { state.write_str(self); } } #[stable(feature = "never_hash", since = "1.29.0")] - impl Hash for ! { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for ! { #[inline] - fn hash(&self, _: &mut H) { + fn hash(&self, _: &mut H) { *self } } @@ -876,9 +900,10 @@ mod impls { macro_rules! impl_hash_tuple { () => ( #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for () { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for () { #[inline] - fn hash(&self, _state: &mut H) {} + fn hash(&self, _state: &mut H) {} } ); @@ -886,10 +911,11 @@ mod impls { maybe_tuple_doc! { $($name)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl<$($name: ~const Hash),+> const Hash for ($($name,)+) where last_type!($($name,)+): ?Sized { #[allow(non_snake_case)] #[inline] - fn hash(&self, state: &mut S) { + fn hash(&self, state: &mut S) { let ($(ref $name,)+) = *self; $($name.hash(state);)+ } @@ -932,24 +958,27 @@ mod impls { impl_hash_tuple! { T B C D E F G H I J K L } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for [T] { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for [T] { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { state.write_length_prefix(self.len()); Hash::hash_slice(self, state) } } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for &T { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for &T { #[inline] - fn hash(&self, state: &mut H) { + fn hash(&self, state: &mut H) { (**self).hash(state); } } #[stable(feature = "rust1", since = "1.0.0")] - impl Hash for &mut T { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + impl const Hash for &mut T { #[inline] fn hash(&self, state: &mut H) { (**self).hash(state); diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 81bf1dfdf4510..7f8287bf56f64 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -118,7 +118,7 @@ macro_rules! load_int_le { /// Safety: this performs unchecked indexing of `buf` at `start..start+len`, so /// that must be in-bounds. #[inline] -unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { +const unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { debug_assert!(len < 8); let mut i = 0; // current byte index (from LSB) in the output u64 let mut out = 0; @@ -138,7 +138,8 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8); i += 1; } - debug_assert_eq!(i, len); + //FIXME(fee1-dead): use debug_assert_eq + debug_assert!(i == len); out } @@ -150,8 +151,9 @@ impl SipHasher { since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead" )] + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub fn new() -> SipHasher { + pub const fn new() -> SipHasher { SipHasher::new_with_keys(0, 0) } @@ -162,8 +164,9 @@ impl SipHasher { since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead" )] + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher { SipHasher(SipHasher24 { hasher: Hasher::new_with_keys(key0, key1) }) } } @@ -176,7 +179,8 @@ impl SipHasher13 { since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead" )] - pub fn new() -> SipHasher13 { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + pub const fn new() -> SipHasher13 { SipHasher13::new_with_keys(0, 0) } @@ -187,14 +191,15 @@ impl SipHasher13 { since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead" )] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] + pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) } } } impl Hasher { #[inline] - fn new_with_keys(key0: u64, key1: u64) -> Hasher { + const fn new_with_keys(key0: u64, key1: u64) -> Hasher { let mut state = Hasher { k0: key0, k1: key1, @@ -209,7 +214,7 @@ impl Hasher { } #[inline] - fn reset(&mut self) { + const fn reset(&mut self) { self.length = 0; self.state.v0 = self.k0 ^ 0x736f6d6570736575; self.state.v1 = self.k1 ^ 0x646f72616e646f6d; @@ -220,7 +225,8 @@ impl Hasher { } #[stable(feature = "rust1", since = "1.0.0")] -impl super::Hasher for SipHasher { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const super::Hasher for SipHasher { #[inline] fn write(&mut self, msg: &[u8]) { self.0.hasher.write(msg) @@ -238,7 +244,8 @@ impl super::Hasher for SipHasher { } #[unstable(feature = "hashmap_internals", issue = "none")] -impl super::Hasher for SipHasher13 { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const super::Hasher for SipHasher13 { #[inline] fn write(&mut self, msg: &[u8]) { self.hasher.write(msg) @@ -255,7 +262,7 @@ impl super::Hasher for SipHasher13 { } } -impl super::Hasher for Hasher { +impl const super::Hasher for Hasher { // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined // for this type. We could add them, copy the `short_write` implementation // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*` @@ -335,7 +342,7 @@ impl super::Hasher for Hasher { } } -impl Clone for Hasher { +impl const Clone for Hasher { #[inline] fn clone(&self) -> Hasher { Hasher { @@ -359,6 +366,7 @@ impl Default for Hasher { } #[doc(hidden)] +#[const_trait] trait Sip { fn c_rounds(_: &mut State); fn d_rounds(_: &mut State); @@ -367,7 +375,7 @@ trait Sip { #[derive(Debug, Clone, Default)] struct Sip13Rounds; -impl Sip for Sip13Rounds { +impl const Sip for Sip13Rounds { #[inline] fn c_rounds(state: &mut State) { compress!(state); @@ -384,7 +392,7 @@ impl Sip for Sip13Rounds { #[derive(Debug, Clone, Default)] struct Sip24Rounds; -impl Sip for Sip24Rounds { +impl const Sip for Sip24Rounds { #[inline] fn c_rounds(state: &mut State) { compress!(state); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 659409557c910..5dc7427bee003 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -112,6 +112,7 @@ #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_fmt_arguments_new)] +#![feature(const_hash)] #![feature(const_heap)] #![feature(const_convert)] #![feature(const_index_range_slice_index)] diff --git a/library/core/tests/hash/mod.rs b/library/core/tests/hash/mod.rs index f7934d062a379..267245f05dcd2 100644 --- a/library/core/tests/hash/mod.rs +++ b/library/core/tests/hash/mod.rs @@ -9,16 +9,19 @@ struct MyHasher { hash: u64, } -impl Default for MyHasher { +impl const Default for MyHasher { fn default() -> MyHasher { MyHasher { hash: 0 } } } -impl Hasher for MyHasher { +impl const Hasher for MyHasher { fn write(&mut self, buf: &[u8]) { - for byte in buf { - self.hash += *byte as u64; + // FIXME(const_trait_impl): change to for loop + let mut i = 0; + while i < buf.len() { + self.hash += buf[i] as u64; + i += 1; } } fn write_str(&mut self, s: &str) { @@ -32,12 +35,25 @@ impl Hasher for MyHasher { #[test] fn test_writer_hasher() { - fn hash(t: &T) -> u64 { + const fn hash(t: &T) -> u64 { let mut s = MyHasher { hash: 0 }; t.hash(&mut s); s.finish() } + const { + // FIXME(fee1-dead): assert_eq + assert!(hash(&()) == 0); + assert!(hash(&5_u8) == 5); + assert!(hash(&5_u16) == 5); + assert!(hash(&5_u32) == 5); + + assert!(hash(&'a') == 97); + + let s: &str = "a"; + assert!(hash(&s) == 97 + 0xFF); + }; + assert_eq!(hash(&()), 0); assert_eq!(hash(&5_u8), 5); @@ -97,7 +113,7 @@ struct CustomHasher { output: u64, } -impl Hasher for CustomHasher { +impl const Hasher for CustomHasher { fn finish(&self) -> u64 { self.output } @@ -109,27 +125,29 @@ impl Hasher for CustomHasher { } } -impl Default for CustomHasher { +impl const Default for CustomHasher { fn default() -> CustomHasher { CustomHasher { output: 0 } } } -impl Hash for Custom { - fn hash(&self, state: &mut H) { +impl const Hash for Custom { + fn hash(&self, state: &mut H) { state.write_u64(self.hash); } } #[test] fn test_custom_state() { - fn hash(t: &T) -> u64 { + const fn hash(t: &T) -> u64 { let mut c = CustomHasher { output: 0 }; t.hash(&mut c); c.finish() } assert_eq!(hash(&Custom { hash: 5 }), 5); + + const { assert!(hash(&Custom { hash: 6 }) == 6) }; } // FIXME: Instantiated functions with i128 in the signature is not supported in Emscripten. diff --git a/library/core/tests/hash/sip.rs b/library/core/tests/hash/sip.rs index 877d084183055..3abf6efcfa9ba 100644 --- a/library/core/tests/hash/sip.rs +++ b/library/core/tests/hash/sip.rs @@ -8,7 +8,6 @@ use core::{mem, slice}; struct Bytes<'a>(&'a [u8]); impl<'a> Hash for Bytes<'a> { - #[allow(unused_must_use)] fn hash(&self, state: &mut H) { let Bytes(v) = *self; state.write(v); @@ -24,6 +23,20 @@ fn hash(x: &T) -> u64 { hash_with(SipHasher::new(), x) } +#[test] +const fn test_const_sip() { + let val1 = 0x45; + let val2 = 0xfeed; + + const fn const_hash(x: &T) -> u64 { + let mut st = SipHasher::new(); + x.hash(&mut st); + st.finish() + } + + assert!(const_hash(&(val1)) != const_hash(&(val2))); +} + #[test] #[allow(unused_must_use)] fn test_siphash_1_3() { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a7db2a02bd743..61d31b3448734 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,6 +11,7 @@ #![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_convert)] +#![feature(const_hash)] #![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_assume_init_read)] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 708edc5de4751..df490358827e7 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -3161,14 +3161,16 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] #[inline] #[allow(deprecated)] + #[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[must_use] - pub fn new() -> DefaultHasher { + pub const fn new() -> DefaultHasher { DefaultHasher(SipHasher13::new_with_keys(0, 0)) } } #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -impl Default for DefaultHasher { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const Default for DefaultHasher { /// Creates a new `DefaultHasher` using [`new`]. /// See its documentation for more. /// @@ -3180,7 +3182,8 @@ impl Default for DefaultHasher { } #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] -impl Hasher for DefaultHasher { +#[rustc_const_unstable(feature = "const_hash", issue = "104061")] +impl const Hasher for DefaultHasher { // The underlying `SipHasher13` doesn't override the other // `write_*` methods, so it's ok not to forward them here. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 385585dada896..9334c833bb650 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -352,6 +352,7 @@ // // Only for const-ness: #![feature(const_collections_with_hasher)] +#![feature(const_hash)] #![feature(const_io_structs)] #![feature(const_ip)] #![feature(const_ipv4)] diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 406bae02d84da..6fd363935079d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -755,6 +755,7 @@ impl<'a> Builder<'a> { run::BuildManifest, run::BumpStage0, run::ReplaceVersionPlaceholder, + run::Miri, ), // These commands either don't use paths, or they're special-cased in Build::build() Kind::Clean | Kind::Format | Kind::Setup => vec![], @@ -818,7 +819,7 @@ impl<'a> Builder<'a> { Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), - Subcommand::Run { ref paths } => (Kind::Run, &paths[..]), + Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]), Subcommand::Format { .. } => (Kind::Format, &[][..]), Subcommand::Clean { .. } | Subcommand::Setup { .. } => { panic!() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ee341a353ac47..2001e29bd2ead 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -140,6 +140,7 @@ pub enum Subcommand { }, Run { paths: Vec, + args: Vec, }, Setup { profile: Profile, @@ -342,6 +343,9 @@ To learn more about a subcommand, run `./x.py -h`", Kind::Format => { opts.optflag("", "check", "check formatting instead of applying."); } + Kind::Run => { + opts.optmulti("", "args", "arguments for the tool", "ARGS"); + } _ => {} }; @@ -613,7 +617,7 @@ Arguments: println!("\nrun requires at least a path!\n"); usage(1, &opts, verbose, &subcommand_help); } - Subcommand::Run { paths } + Subcommand::Run { paths, args: matches.opt_strs("args") } } Kind::Setup => { let profile = if paths.len() > 1 { @@ -721,16 +725,12 @@ impl Subcommand { } pub fn test_args(&self) -> Vec<&str> { - let mut args = vec![]; - match *self { Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { - args.extend(test_args.iter().flat_map(|s| s.split_whitespace())) + test_args.iter().flat_map(|s| s.split_whitespace()).collect() } - _ => (), + _ => vec![], } - - args } pub fn rustc_args(&self) -> Vec<&str> { @@ -738,7 +738,16 @@ impl Subcommand { Subcommand::Test { ref rustc_args, .. } => { rustc_args.iter().flat_map(|s| s.split_whitespace()).collect() } - _ => Vec::new(), + _ => vec![], + } + } + + pub fn args(&self) -> Vec<&str> { + match *self { + Subcommand::Run { ref args, .. } => { + args.iter().flat_map(|s| s.split_whitespace()).collect() + } + _ => vec![], } } diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 511872903d14e..d49b41c513279 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,8 +1,12 @@ +use std::process::Command; + use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::config::TargetSelection; use crate::dist::distdir; -use crate::tool::Tool; +use crate::test; +use crate::tool::{self, SourceType, Tool}; use crate::util::output; -use std::process::Command; +use crate::Mode; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct ExpandYamlAnchors; @@ -125,3 +129,63 @@ impl Step for ReplaceVersionPlaceholder { builder.run(&mut cmd); } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Miri { + stage: u32, + host: TargetSelection, + target: TargetSelection, +} + +impl Step for Miri { + type Output = (); + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/miri") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Miri { + stage: run.builder.top_stage, + host: run.build_triple(), + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) { + let stage = self.stage; + let host = self.host; + let target = self.target; + let compiler = builder.compiler(stage, host); + + let miri = builder + .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }) + .expect("in-tree tool"); + let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target); + + // # Run miri. + // Running it via `cargo run` as that figures out the right dylib path. + // add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so. + let mut miri = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolRustc, + host, + "run", + "src/tools/miri", + SourceType::InTree, + &[], + ); + miri.add_rustc_lib_path(builder, compiler); + // Forward arguments. + miri.arg("--").arg("--target").arg(target.rustc_target_arg()); + miri.args(builder.config.cmd.args()); + + // miri tests need to know about the stage sysroot + miri.env("MIRI_SYSROOT", &miri_sysroot); + + let mut miri = Command::from(miri); + builder.run(&mut miri); + } +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 931d9a67944df..2b2257b72ae79 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -465,49 +465,20 @@ pub struct Miri { target: TargetSelection, } -impl Step for Miri { - type Output = (); - const ONLY_HOSTS: bool = false; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/miri") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Miri { - stage: run.builder.top_stage, - host: run.build_triple(), - target: run.target, - }); - } - - /// Runs `cargo test` for miri. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let host = self.host; - let target = self.target; - let compiler = builder.compiler(stage, host); - // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri. - // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage. - let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host); - - let miri = builder - .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }) - .expect("in-tree tool"); - let _cargo_miri = builder - .ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() }) - .expect("in-tree tool"); - // The stdlib we need might be at a different stage. And just asking for the - // sysroot does not seem to populate it, so we do that first. - builder.ensure(compile::Std::new(compiler_std, host)); - let sysroot = builder.sysroot(compiler_std); - - // # Run `cargo miri setup` for the given target. +impl Miri { + /// Run `cargo miri setup` for the given target, return where the Miri sysroot was put. + pub fn build_miri_sysroot( + builder: &Builder<'_>, + compiler: Compiler, + miri: &Path, + target: TargetSelection, + ) -> String { + let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysrot"); let mut cargo = tool::prepare_tool_cargo( builder, compiler, Mode::ToolRustc, - host, + compiler.host, "run", "src/tools/miri/cargo-miri", SourceType::InTree, @@ -521,6 +492,8 @@ impl Step for Miri { cargo.env("MIRI_LIB_SRC", builder.src.join("library")); // Tell it where to find Miri. cargo.env("MIRI", &miri); + // Tell it where to put the sysroot. + cargo.env("MIRI_SYSROOT", &miri_sysroot); // Debug things. cargo.env("RUST_BACKTRACE", "1"); @@ -535,7 +508,7 @@ impl Step for Miri { cargo.arg("--print-sysroot"); // FIXME: Is there a way in which we can re-use the usual `run` helpers? - let miri_sysroot = if builder.config.dry_run { + if builder.config.dry_run { String::new() } else { builder.verbose(&format!("running: {:?}", cargo)); @@ -548,7 +521,48 @@ impl Step for Miri { let sysroot = stdout.trim_end(); builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot)); sysroot.to_owned() - }; + } + } +} + +impl Step for Miri { + type Output = (); + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/miri") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Miri { + stage: run.builder.top_stage, + host: run.build_triple(), + target: run.target, + }); + } + + /// Runs `cargo test` for miri. + fn run(self, builder: &Builder<'_>) { + let stage = self.stage; + let host = self.host; + let target = self.target; + let compiler = builder.compiler(stage, host); + // We need the stdlib for the *next* stage, as it was built with this compiler that also built Miri. + // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage. + let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host); + + let miri = builder + .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() }) + .expect("in-tree tool"); + let _cargo_miri = builder + .ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() }) + .expect("in-tree tool"); + // The stdlib we need might be at a different stage. And just asking for the + // sysroot does not seem to populate it, so we do that first. + builder.ensure(compile::Std::new(compiler_std, host)); + let sysroot = builder.sysroot(compiler_std); + // We also need a Miri sysroot. + let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target); // # Run `cargo test`. let mut cargo = tool::prepare_tool_cargo( @@ -566,7 +580,6 @@ impl Step for Miri { // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); cargo.env("MIRI_HOST_SYSROOT", sysroot); - cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", &miri); // propagate --bless if builder.config.cmd.bless() { @@ -607,7 +620,6 @@ impl Step for Miri { // Tell `cargo miri` where to find things. cargo.env("MIRI_SYSROOT", &miri_sysroot); cargo.env("MIRI_HOST_SYSROOT", sysroot); - cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", &miri); // Debug things. cargo.env("RUST_BACKTRACE", "1"); diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index cc96715b28572..ed0d9e9902b99 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.12.7 \ No newline at end of file +0.13.1 \ No newline at end of file diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f58d2c609426d..86a5b0b303f39 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -830,6 +830,9 @@ table, line-height: 1.5; font-weight: 500; } +#crate-search:hover, #crate-search:focus { + border-color: var(--crate-search-hover-border); +} /* cancel stylistic differences in padding in firefox for "appearance: none"-style (or equivalent) ` isn't bigger than its container (".search-results-title"). assert-css: ("#search", {"width": "640px"}) + +// Now checking that the crate filter is working as expected too. +show-text: true +define-function: ( + "check-filter", + (theme, border, filter, hover_border, hover_filter), + [ + ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}), + ("reload"), + ("wait-for", "#crate-search"), + ("assert-css", ("#crate-search", {"border": "1px solid " + |border|})), + ("assert-css", ("#crate-search-div::after", {"filter": |filter|})), + ("move-cursor-to", "#crate-search"), + ("assert-css", ("#crate-search", {"border": "1px solid " + |hover_border|})), + ("assert-css", ("#crate-search-div::after", {"filter": |hover_filter|})), + ("move-cursor-to", ".search-input"), + ], +) + +call-function: ("check-filter", { + "theme": "ayu", + "border": "rgb(92, 103, 115)", + "filter": "invert(0.41) sepia(0.12) saturate(4.87) hue-rotate(171deg) brightness(0.94) contrast(0.94)", + "hover_border": "rgb(224, 224, 224)", + "hover_filter": "invert(0.98) sepia(0.12) saturate(0.81) hue-rotate(343deg) brightness(1.13) contrast(0.76)", +}) +call-function: ("check-filter", { + "theme": "dark", + "border": "rgb(224, 224, 224)", + "filter": "invert(0.94) sepia(0) saturate(7.21) hue-rotate(255deg) brightness(0.9) contrast(0.9)", + "hover_border": "rgb(33, 150, 243)", + "hover_filter": "invert(0.69) sepia(0.6) saturate(66.13) hue-rotate(184deg) brightness(1) contrast(0.91)", +}) +call-function: ("check-filter", { + "theme": "light", + "border": "rgb(224, 224, 224)", + "filter": "invert(1) sepia(0) saturate(42.23) hue-rotate(289deg) brightness(1.14) contrast(0.76)", + "hover_border": "rgb(113, 113, 113)", + "hover_filter": "invert(0.44) sepia(0.18) saturate(0.23) hue-rotate(317deg) brightness(0.96) contrast(0.93)", +}) diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml index a799444a1087e..e5d023544d682 100644 --- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml +++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml @@ -1,4 +1,9 @@ // Checks that the elements in the sidebar are alphabetically sorted. + +// We need to disable this check because `implementors/test_docs/trait.AnotherOne.js` +// doesn't exist. +fail-on-request-error: false + goto: "file://" + |DOC_PATH| + "/test_docs/trait.AnotherOne.html" assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another") assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1") diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml index fce3002e7508f..dcffe956c2197 100644 --- a/src/test/rustdoc-gui/type-declation-overflow.goml +++ b/src/test/rustdoc-gui/type-declation-overflow.goml @@ -1,4 +1,10 @@ // This test ensures that the items declaration content overflow is handled inside the
 directly.
+
+// We need to disable this check because
+// `implementors/test_docs/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.js`
+// doesn't exist.
+fail-on-request-error: false
+
 goto: "file://" + |DOC_PATH| + "/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html"
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
diff --git a/src/test/ui/did_you_mean/issue-103909.stderr b/src/test/ui/did_you_mean/issue-103909.stderr
index a28914051b980..8641017470ba0 100644
--- a/src/test/ui/did_you_mean/issue-103909.stderr
+++ b/src/test/ui/did_you_mean/issue-103909.stderr
@@ -14,6 +14,11 @@ error[E0308]: mismatched types
    |
 LL |     if Err(err) = File::open("hello.txt") {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Err(err) = File::open("hello.txt") {
+   |        +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/inference/issue-103587.rs b/src/test/ui/inference/issue-103587.rs
new file mode 100644
index 0000000000000..11536f9f4cc48
--- /dev/null
+++ b/src/test/ui/inference/issue-103587.rs
@@ -0,0 +1,12 @@
+fn main() {
+    let x = Some(123);
+
+    if let Some(_) == x {}
+    //~^ ERROR expected `=`, found `==`
+
+    if Some(_) = x {}
+    //~^ ERROR mismatched types
+
+    if None = x { }
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/issue-103587.stderr b/src/test/ui/inference/issue-103587.stderr
new file mode 100644
index 0000000000000..b373fbfbb948c
--- /dev/null
+++ b/src/test/ui/inference/issue-103587.stderr
@@ -0,0 +1,40 @@
+error: expected `=`, found `==`
+  --> $DIR/issue-103587.rs:4:20
+   |
+LL |     if let Some(_) == x {}
+   |                    ^^
+   |
+help: consider using `=` here
+   |
+LL |     if let Some(_) = x {}
+   |                    ~
+
+error[E0308]: mismatched types
+  --> $DIR/issue-103587.rs:7:8
+   |
+LL |     if Some(_) = x {}
+   |        ^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(_) = x {}
+   |        +++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-103587.rs:10:8
+   |
+LL |     if None = x { }
+   |        ^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to use pattern matching
+   |
+LL |     if let None = x { }
+   |        +++
+help: you might have meant to compare for equality
+   |
+LL |     if None == x { }
+   |              +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/use-colon-as-mod-sep.rs b/src/test/ui/parser/use-colon-as-mod-sep.rs
new file mode 100644
index 0000000000000..e1e8756b03c26
--- /dev/null
+++ b/src/test/ui/parser/use-colon-as-mod-sep.rs
@@ -0,0 +1,11 @@
+// Recover from using a colon as a path separator.
+
+use std::process:Command;
+//~^ ERROR expected `::`, found `:`
+use std:fs::File;
+//~^ ERROR expected `::`, found `:`
+use std:collections:HashMap;
+//~^ ERROR expected `::`, found `:`
+//~| ERROR expected `::`, found `:`
+
+fn main() { }
diff --git a/src/test/ui/parser/use-colon-as-mod-sep.stderr b/src/test/ui/parser/use-colon-as-mod-sep.stderr
new file mode 100644
index 0000000000000..e825dfed11192
--- /dev/null
+++ b/src/test/ui/parser/use-colon-as-mod-sep.stderr
@@ -0,0 +1,28 @@
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:3:17
+   |
+LL | use std::process:Command;
+   |                 ^ help: use double colon
+   |
+   = note: import paths are delimited using `::`
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:5:8
+   |
+LL | use std:fs::File;
+   |        ^ help: use double colon
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:7:8
+   |
+LL | use std:collections:HashMap;
+   |        ^ help: use double colon
+
+error: expected `::`, found `:`
+  --> $DIR/use-colon-as-mod-sep.rs:7:20
+   |
+LL | use std:collections:HashMap;
+   |                    ^ help: use double colon
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/suggestions/if-let-typo.stderr b/src/test/ui/suggestions/if-let-typo.stderr
index 3d9ac40ec367b..02148b7f7adfd 100644
--- a/src/test/ui/suggestions/if-let-typo.stderr
+++ b/src/test/ui/suggestions/if-let-typo.stderr
@@ -25,12 +25,22 @@ error[E0308]: mismatched types
    |
 LL |     if Some(x) = foo {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(x) = foo {}
+   |        +++
 
 error[E0308]: mismatched types
   --> $DIR/if-let-typo.rs:6:8
    |
 LL |     if Some(foo) = bar {}
    |        ^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(foo) = bar {}
+   |        +++
 
 error[E0308]: mismatched types
   --> $DIR/if-let-typo.rs:7:8
@@ -51,6 +61,11 @@ error[E0308]: mismatched types
    |
 LL |     if Some(3) = foo {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |     if let Some(3) = foo {}
+   |        +++
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/type/issue-103271.rs b/src/test/ui/type/issue-103271.rs
new file mode 100644
index 0000000000000..bd3254af3df71
--- /dev/null
+++ b/src/test/ui/type/issue-103271.rs
@@ -0,0 +1,10 @@
+fn main() {
+    let iter_fun = <&[u32]>::iter;
+    //~^ ERROR no function or associated item named `iter` found for reference `&[u32]` in the current scope [E0599]
+    //~| function or associated item not found in `&[u32]`
+    //~| HELP the function `iter` is implemented on `[u32]`
+    for item in iter_fun(&[1,1]) {
+        let x: &u32 = item;
+        assert_eq!(x, &1);
+    }
+}
diff --git a/src/test/ui/type/issue-103271.stderr b/src/test/ui/type/issue-103271.stderr
new file mode 100644
index 0000000000000..02a59d4b99c4d
--- /dev/null
+++ b/src/test/ui/type/issue-103271.stderr
@@ -0,0 +1,14 @@
+error[E0599]: no function or associated item named `iter` found for reference `&[u32]` in the current scope
+  --> $DIR/issue-103271.rs:2:30
+   |
+LL |     let iter_fun = <&[u32]>::iter;
+   |                              ^^^^ function or associated item not found in `&[u32]`
+   |
+help: the function `iter` is implemented on `[u32]`
+   |
+LL |     let iter_fun = <[u32]>::iter;
+   |                     ~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
index 878897c410cf5..4506d1550bd4b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -23,6 +23,11 @@ error[E0308]: mismatched types
    |
 LL |         Some(reference) = cache.data.get(key) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: consider adding `let`
+   |
+LL |         let Some(reference) = cache.data.get(key) {
+   |         +++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 5803a88c0e757..f5a20d592d06d 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -433,8 +433,10 @@ Moreover, Miri recognizes some environment variables:
   trigger a re-build of the standard library; you have to clear the Miri build
   cache manually (on Linux, `rm -rf ~/.cache/miri`).
 * `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
-  using `cargo miri`, only set this if you do not want to use the automatically created sysroot. For
-  directly invoking the Miri driver, this variable (or a `--sysroot` flag) is mandatory.
+  using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the
+  automatically created sysroot. For directly invoking the Miri driver, this variable (or a
+  `--sysroot` flag) is mandatory. When invoking `cargo miri setup`, this indicates where the sysroot
+  will be put.
 * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target
   architecture to test against.  `miri` and `cargo miri` accept the `--target` flag for the same
   purpose.
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index 72d8ef2f75224..f3841a6140839 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -17,10 +17,8 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
     let only_setup = matches!(subcommand, MiriCommand::Setup);
     let ask_user = !only_setup;
     let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
-    if std::env::var_os("MIRI_SYSROOT").is_some() {
-        if only_setup {
-            println!("WARNING: MIRI_SYSROOT already set, not doing anything.")
-        }
+    if !only_setup && std::env::var_os("MIRI_SYSROOT").is_some() {
+        // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
         return;
     }
 
@@ -61,8 +59,13 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
     }
 
     // Determine where to put the sysroot.
-    let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
-    let sysroot_dir = user_dirs.cache_dir();
+    let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
+        Some(dir) => PathBuf::from(dir),
+        None => {
+            let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
+            user_dirs.cache_dir().to_owned()
+        }
+    };
     // Sysroot configuration and build details.
     let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() {
         SysrootConfig::NoStd
@@ -111,7 +114,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         (command, rustflags)
     };
     // Make sure all target-level Miri invocations know their sysroot.
-    std::env::set_var("MIRI_SYSROOT", sysroot_dir);
+    std::env::set_var("MIRI_SYSROOT", &sysroot_dir);
 
     // Do the build.
     if only_setup {
@@ -121,7 +124,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
         // We want to be quiet, but still let the user know that something is happening.
         eprint!("Preparing a sysroot for Miri (target: {target})... ");
     }
-    Sysroot::new(sysroot_dir, target)
+    Sysroot::new(&sysroot_dir, target)
         .build_from_source(&rust_src, BuildMode::Check, sysroot_config, rustc_version, cargo_cmd)
         .unwrap_or_else(|_| {
             if only_setup {
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 70d5f94472f6b..d40d9a3cb542a 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -149,6 +149,7 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         let args = [
             "--variable", "DOC_PATH", opts["doc_folder"], "--enable-fail-on-js-error",
+            "--allow-file-access-from-files",
         ];
         if (opts["debug"]) {
             debug = true;