diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4ae18b4cf4854..31dd358ad51f4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -403,9 +403,10 @@ impl Default for Generics { /// A where-clause in a definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WhereClause { - /// `true` if we ate a `where` token: this can happen - /// if we parsed no predicates (e.g. `struct Foo where {}`). - /// This allows us to pretty-print accurately. + /// `true` if we ate a `where` token. + /// + /// This can happen if we parsed no predicates, e.g., `struct Foo where {}`. + /// This allows us to pretty-print accurately and provide correct suggestion diagnostics. pub has_where_token: bool, pub predicates: ThinVec, pub span: Span, @@ -3007,18 +3008,29 @@ pub struct Trait { /// /// If there is no where clause, then this is `false` with `DUMMY_SP`. #[derive(Copy, Clone, Encodable, Decodable, Debug, Default)] -pub struct TyAliasWhereClause(pub bool, pub Span); +pub struct TyAliasWhereClause { + pub has_where_token: bool, + pub span: Span, +} + +/// The span information for the two where clauses on a `TyAlias`. +#[derive(Copy, Clone, Encodable, Decodable, Debug, Default)] +pub struct TyAliasWhereClauses { + /// Before the equals sign. + pub before: TyAliasWhereClause, + /// After the equals sign. + pub after: TyAliasWhereClause, + /// The index in `TyAlias.generics.where_clause.predicates` that would split + /// into predicates from the where clause before the equals sign and the ones + /// from the where clause after the equals sign. + pub split: usize, +} #[derive(Clone, Encodable, Decodable, Debug)] pub struct TyAlias { pub defaultness: Defaultness, pub generics: Generics, - /// The span information for the two where clauses (before equals, after equals) - pub where_clauses: (TyAliasWhereClause, TyAliasWhereClause), - /// The index in `generics.where_clause.predicates` that would split into - /// predicates from the where clause before the equals and the predicates - /// from the where clause after the equals - pub where_predicates_split: usize, + pub where_clauses: TyAliasWhereClauses, pub bounds: GenericBounds, pub ty: Option>, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 60bc21c6441fc..2faf3228d551e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1079,8 +1079,8 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { }) => { visit_defaultness(defaultness, vis); vis.visit_generics(generics); - vis.visit_span(&mut where_clauses.0.1); - vis.visit_span(&mut where_clauses.1.1); + vis.visit_span(&mut where_clauses.before.span); + vis.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, vis); visit_opt(ty, |ty| vis.visit_ty(ty)); } @@ -1163,8 +1163,8 @@ pub fn noop_flat_map_assoc_item( }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.0.1); - visitor.visit_span(&mut where_clauses.1.1); + visitor.visit_span(&mut where_clauses.before.span); + visitor.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } @@ -1257,8 +1257,8 @@ pub fn noop_flat_map_foreign_item( }) => { visit_defaultness(defaultness, visitor); visitor.visit_generics(generics); - visitor.visit_span(&mut where_clauses.0.1); - visitor.visit_span(&mut where_clauses.1.1); + visitor.visit_span(&mut where_clauses.before.span); + visitor.visit_span(&mut where_clauses.after.span); visit_bounds(bounds, visitor); visit_opt(ty, |ty| visitor.visit_ty(ty)); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 87ed47648c813..01b1e6fcaff64 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -33,19 +33,20 @@ pub(super) struct ItemLowerer<'a, 'hir> { /// clause if it exists. fn add_ty_alias_where_clause( generics: &mut ast::Generics, - mut where_clauses: (TyAliasWhereClause, TyAliasWhereClause), + mut where_clauses: TyAliasWhereClauses, prefer_first: bool, ) { if !prefer_first { - where_clauses = (where_clauses.1, where_clauses.0); - } - if where_clauses.0.0 || !where_clauses.1.0 { - generics.where_clause.has_where_token = where_clauses.0.0; - generics.where_clause.span = where_clauses.0.1; - } else { - generics.where_clause.has_where_token = where_clauses.1.0; - generics.where_clause.span = where_clauses.1.1; + (where_clauses.before, where_clauses.after) = (where_clauses.after, where_clauses.before); } + let where_clause = + if where_clauses.before.has_where_token || !where_clauses.after.has_where_token { + where_clauses.before + } else { + where_clauses.after + }; + generics.where_clause.has_where_token = where_clause.has_where_token; + generics.where_clause.span = where_clause.span; } impl<'a, 'hir> ItemLowerer<'a, 'hir> { diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 6586ca5d36f88..28a13d275a559 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -280,4 +280,5 @@ ast_passes_where_clause_after_type_alias = where clauses are not allowed after t ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases .note = see issue #89122 for more information - .suggestion = move it to the end of the type declaration + .remove_suggestion = remove this `where` + .move_suggestion = move it to the end of the type declaration diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 8c9ad83608761..b56d695c6716a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -138,38 +138,42 @@ impl<'a> AstValidator<'a> { &mut self, ty_alias: &TyAlias, ) -> Result<(), errors::WhereClauseBeforeTypeAlias> { - let before_predicates = - ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0; - - if ty_alias.ty.is_none() || before_predicates.is_empty() { + if ty_alias.ty.is_none() || !ty_alias.where_clauses.before.has_where_token { return Ok(()); } - let mut state = State::new(); - if !ty_alias.where_clauses.1.0 { - state.space(); - state.word_space("where"); - } else { - state.word_space(","); - } - let mut first = true; - for p in before_predicates { - if !first { - state.word_space(","); + let (before_predicates, after_predicates) = + ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_clauses.split); + let span = ty_alias.where_clauses.before.span; + + let sugg = if !before_predicates.is_empty() || !ty_alias.where_clauses.after.has_where_token + { + let mut state = State::new(); + + if !ty_alias.where_clauses.after.has_where_token { + state.space(); + state.word_space("where"); } - first = false; - state.print_where_predicate(p); - } - let span = ty_alias.where_clauses.0.1; - Err(errors::WhereClauseBeforeTypeAlias { - span, - sugg: errors::WhereClauseBeforeTypeAliasSugg { + let mut first = after_predicates.is_empty(); + for p in before_predicates { + if !first { + state.word_space(","); + } + first = false; + state.print_where_predicate(p); + } + + errors::WhereClauseBeforeTypeAliasSugg::Move { left: span, snippet: state.s.eof(), - right: ty_alias.where_clauses.1.1.shrink_to_hi(), - }, - }) + right: ty_alias.where_clauses.after.span.shrink_to_hi(), + } + } else { + errors::WhereClauseBeforeTypeAliasSugg::Remove { span } + }; + + Err(errors::WhereClauseBeforeTypeAlias { span, sugg }) } fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { @@ -457,8 +461,7 @@ impl<'a> AstValidator<'a> { fn check_foreign_ty_genericless( &self, generics: &Generics, - before_where_clause: &TyAliasWhereClause, - after_where_clause: &TyAliasWhereClause, + where_clauses: &TyAliasWhereClauses, ) { let cannot_have = |span, descr, remove_descr| { self.dcx().emit_err(errors::ExternTypesCannotHave { @@ -473,14 +476,14 @@ impl<'a> AstValidator<'a> { cannot_have(generics.span, "generic parameters", "generic parameters"); } - let check_where_clause = |where_clause: &TyAliasWhereClause| { - if let TyAliasWhereClause(true, where_clause_span) = where_clause { - cannot_have(*where_clause_span, "`where` clauses", "`where` clause"); + let check_where_clause = |where_clause: TyAliasWhereClause| { + if where_clause.has_where_token { + cannot_have(where_clause.span, "`where` clauses", "`where` clause"); } }; - check_where_clause(before_where_clause); - check_where_clause(after_where_clause); + check_where_clause(where_clauses.before); + check_where_clause(where_clauses.after); } fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option) { @@ -1122,9 +1125,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { self.dcx().emit_err(err); } - } else if where_clauses.1.0 { + } else if where_clauses.after.has_where_token { self.dcx().emit_err(errors::WhereClauseAfterTypeAlias { - span: where_clauses.1.1, + span: where_clauses.after.span, help: self.session.is_nightly_build().then_some(()), }); } @@ -1154,7 +1157,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_defaultness(fi.span, *defaultness); self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span)); self.check_type_no_bounds(bounds, "`extern` blocks"); - self.check_foreign_ty_genericless(generics, &where_clauses.0, &where_clauses.1); + self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } ForeignItemKind::Static(_, _, body) => { @@ -1477,15 +1480,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if let AssocItemKind::Type(ty_alias) = &item.kind && let Err(err) = self.check_type_alias_where_clause_location(ty_alias) { + let sugg = match err.sugg { + errors::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None, + errors::WhereClauseBeforeTypeAliasSugg::Move { snippet, right, .. } => { + Some((right, snippet)) + } + }; self.lint_buffer.buffer_lint_with_diagnostic( DEPRECATED_WHERE_CLAUSE_LOCATION, item.id, err.span, fluent::ast_passes_deprecated_where_clause_location, - BuiltinLintDiagnostics::DeprecatedWhereclauseLocation( - err.sugg.right, - err.sugg.snippet, - ), + BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg), ); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index e5153c8979039..8275b34b63b95 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -516,17 +516,25 @@ pub struct WhereClauseBeforeTypeAlias { } #[derive(Subdiagnostic)] -#[multipart_suggestion( - ast_passes_suggestion, - applicability = "machine-applicable", - style = "verbose" -)] -pub struct WhereClauseBeforeTypeAliasSugg { - #[suggestion_part(code = "")] - pub left: Span, - pub snippet: String, - #[suggestion_part(code = "{snippet}")] - pub right: Span, + +pub enum WhereClauseBeforeTypeAliasSugg { + #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")] + Remove { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + ast_passes_move_suggestion, + applicability = "machine-applicable", + style = "verbose" + )] + Move { + #[suggestion_part(code = "")] + left: Span, + snippet: String, + #[suggestion_part(code = "{snippet}")] + right: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 584f01e16c2c3..13f27c1c95c2e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -43,7 +43,6 @@ impl<'a> State<'a> { defaultness, generics, where_clauses, - where_predicates_split, bounds, ty, }) => { @@ -51,7 +50,6 @@ impl<'a> State<'a> { ident, generics, *where_clauses, - *where_predicates_split, bounds, ty.as_deref(), vis, @@ -108,15 +106,14 @@ impl<'a> State<'a> { &mut self, ident: Ident, generics: &ast::Generics, - where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause), - where_predicates_split: usize, + where_clauses: ast::TyAliasWhereClauses, bounds: &ast::GenericBounds, ty: Option<&ast::Ty>, vis: &ast::Visibility, defaultness: ast::Defaultness, ) { let (before_predicates, after_predicates) = - generics.where_clause.predicates.split_at(where_predicates_split); + generics.where_clause.predicates.split_at(where_clauses.split); self.head(""); self.print_visibility(vis); self.print_defaultness(defaultness); @@ -127,13 +124,13 @@ impl<'a> State<'a> { self.word_nbsp(":"); self.print_type_bounds(bounds); } - self.print_where_clause_parts(where_clauses.0.0, before_predicates); + self.print_where_clause_parts(where_clauses.before.has_where_token, before_predicates); if let Some(ty) = ty { self.space(); self.word_space("="); self.print_type(ty); } - self.print_where_clause_parts(where_clauses.1.0, after_predicates); + self.print_where_clause_parts(where_clauses.after.has_where_token, after_predicates); self.word(";"); self.end(); // end inner head-block self.end(); // end outer head-block @@ -249,7 +246,6 @@ impl<'a> State<'a> { defaultness, generics, where_clauses, - where_predicates_split, bounds, ty, }) => { @@ -257,7 +253,6 @@ impl<'a> State<'a> { item.ident, generics, *where_clauses, - *where_predicates_split, bounds, ty.as_deref(), &item.vis, @@ -536,7 +531,6 @@ impl<'a> State<'a> { defaultness, generics, where_clauses, - where_predicates_split, bounds, ty, }) => { @@ -544,7 +538,6 @@ impl<'a> State<'a> { ident, generics, *where_clauses, - *where_predicates_split, bounds, ty.as_deref(), vis, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3ee4fded74999..eb664b571ba85 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -601,11 +601,7 @@ impl<'a> TraitDef<'a> { kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias { defaultness: ast::Defaultness::Final, generics: Generics::default(), - where_clauses: ( - ast::TyAliasWhereClause::default(), - ast::TyAliasWhereClause::default(), - ), - where_predicates_split: 0, + where_clauses: ast::TyAliasWhereClauses::default(), bounds: Vec::new(), ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), })), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 65c49a6085c4e..ea536882d1274 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -108,6 +108,25 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { /// Trait implemented by error types. This is rarely implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. +/// +/// When implemented manually, it should be generic over the emission +/// guarantee, i.e.: +/// ```ignore (fragment) +/// impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for Foo { ... } +/// ``` +/// rather than being specific: +/// ```ignore (fragment) +/// impl<'a> IntoDiagnostic<'a> for Bar { ... } // the default type param is `ErrorGuaranteed` +/// impl<'a> IntoDiagnostic<'a, ()> for Baz { ... } +/// ``` +/// There are two reasons for this. +/// - A diagnostic like `Foo` *could* be emitted at any level -- `level` is +/// passed in to `into_diagnostic` from outside. Even if in practice it is +/// always emitted at a single level, we let the diagnostic creation/emission +/// site determine the level (by using `create_err`, `emit_warn`, etc.) +/// rather than the `IntoDiagnostic` impl. +/// - Derived impls are always generic, and it's good for the hand-written +/// impls to be consistent with them. #[rustc_diagnostic_item = "IntoDiagnostic"] pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3f667e264e85f..3559afeced8ba 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1514,14 +1514,26 @@ impl DiagCtxtInner { let bugs: Vec<_> = std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); - // If backtraces are enabled, also print the query stack let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); - for (i, bug) in bugs.into_iter().enumerate() { - if let Some(file) = self.ice_file.as_ref() - && let Ok(mut out) = std::fs::File::options().create(true).append(true).open(file) - { - let _ = write!( - &mut out, + let decorate = backtrace || self.ice_file.is_none(); + let mut out = self + .ice_file + .as_ref() + .and_then(|file| std::fs::File::options().create(true).append(true).open(file).ok()); + + // Put the overall explanation before the `DelayedBug`s, to frame them + // better (e.g. separate warnings from them). Also, use notes, which + // don't count as errors, to avoid possibly triggering + // `-Ztreat-err-as-bug`, which we don't want. + let note1 = "no errors encountered even though delayed bugs were created"; + let note2 = "those delayed bugs will now be shown as internal compiler errors"; + self.emit_diagnostic(Diagnostic::new(Note, note1)); + self.emit_diagnostic(Diagnostic::new(Note, note2)); + + for bug in bugs { + if let Some(out) = &mut out { + _ = write!( + out, "delayed bug: {}\n{}\n", bug.inner .messages @@ -1532,21 +1544,9 @@ impl DiagCtxtInner { ); } - if i == 0 { - // Put the overall explanation before the `DelayedBug`s, to - // frame them better (e.g. separate warnings from them). Also, - // make it a note so it doesn't count as an error, because that - // could trigger `-Ztreat-err-as-bug`, which we don't want. - let note1 = "no errors encountered even though delayed bugs were created"; - let note2 = "those delayed bugs will now be shown as internal compiler errors"; - self.emit_diagnostic(Diagnostic::new(Note, note1)); - self.emit_diagnostic(Diagnostic::new(Note, note2)); - } - - let mut bug = - if backtrace || self.ice_file.is_none() { bug.decorate(self) } else { bug.inner }; + let mut bug = if decorate { bug.decorate(self) } else { bug.inner }; - // "Undelay" the delayed bugs (into plain `Bug`s). + // "Undelay" the delayed bugs into plain bugs. if bug.level != DelayedBug { // NOTE(eddyb) not panicking here because we're already producing // an ICE, and the more information the merrier. diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9a130ed7f543d..9bba7bbd47a5e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1257,10 +1257,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { let did1 = def1.did(); let did2 = def2.did(); - let sub_no_defaults_1 = - self.tcx.generics_of(did1).own_args_no_defaults(self.tcx, sub1); - let sub_no_defaults_2 = - self.tcx.generics_of(did2).own_args_no_defaults(self.tcx, sub2); + + let generics1 = self.tcx.generics_of(did1); + let generics2 = self.tcx.generics_of(did2); + + let non_default_after_default = generics1 + .check_concrete_type_after_default(self.tcx, sub1) + || generics2.check_concrete_type_after_default(self.tcx, sub2); + let sub_no_defaults_1 = if non_default_after_default { + generics1.own_args(sub1) + } else { + generics1.own_args_no_defaults(self.tcx, sub1) + }; + let sub_no_defaults_2 = if non_default_after_default { + generics2.own_args(sub2) + } else { + generics2.own_args_no_defaults(self.tcx, sub2) + }; let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); let path1 = self.tcx.def_path_str(did1); let path2 = self.tcx.def_path_str(did2); diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index c0a99e5cc4177..8dd3a1f40cc10 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -62,6 +62,7 @@ use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; +use crate::infer::resolve::OpportunisticRegionResolver; use crate::infer::{ self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, }; @@ -69,7 +70,9 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgsRef, Region, Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt, +}; use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_span::DUMMY_SP; use smallvec::smallvec; @@ -176,6 +179,11 @@ impl<'tcx> InferCtxt<'tcx> { .map_err(|NoSolution| (outlives, origin.clone()))? .no_bound_vars() .expect("started with no bound vars, should end with no bound vars"); + // `TypeOutlives` is structural, so we should try to opportunistically resolve all + // region vids before processing regions, so we have a better chance to match clauses + // in our param-env. + let (sup_type, sub_region) = + (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); debug!(?sup_type, ?sub_region, ?origin); diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 86434002e2c66..c70a9b4f93263 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -430,15 +430,22 @@ pub(super) fn builtin( db.note("see for more information about checking conditional configuration"); } } - BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => { - db.multipart_suggestion( - "move it to the end of the type declaration", - vec![(db.span.primary_span().unwrap(), "".to_string()), (new_span, suggestion)], - Applicability::MachineApplicable, - ); - db.note( - "see issue #89122 for more information", - ); + BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(sugg) => { + let left_sp = db.span.primary_span().unwrap(); + match sugg { + Some((right_sp, sugg)) => db.multipart_suggestion( + "move it to the end of the type declaration", + vec![(left_sp, String::new()), (right_sp, sugg)], + Applicability::MachineApplicable, + ), + None => db.span_suggestion( + left_sp, + "remove this `where`", + "", + Applicability::MachineApplicable, + ), + }; + db.note("see issue #89122 for more information"); } BuiltinLintDiagnostics::SingleUseLifetime { param_span, diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d4e5c78c492c7..d261814402c7c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -597,7 +597,7 @@ pub enum BuiltinLintDiagnostics { UnicodeTextFlow(Span, String), UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - DeprecatedWhereclauseLocation(Span, String), + DeprecatedWhereclauseLocation(Option<(Span, String)>), SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index c81d9dfbc7d60..2630b96869bae 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -360,6 +360,30 @@ impl<'tcx> Generics { let own = &args[self.parent_count..][..self.params.len()]; if self.has_self && self.parent.is_none() { &own[1..] } else { own } } + + /// Returns true if a concrete type is specified after a default type. + /// For example, consider `struct T>(W, X)` + /// `T` will return true + /// `T` will return false + pub fn check_concrete_type_after_default( + &'tcx self, + tcx: TyCtxt<'tcx>, + args: &'tcx [ty::GenericArg<'tcx>], + ) -> bool { + let mut default_param_seen = false; + for param in self.params.iter() { + if let Some(inst) = + param.default_value(tcx).map(|default| default.instantiate(tcx, args)) + { + if inst == args[param.index as usize] { + default_param_seen = true; + } else if default_param_seen { + return true; + } + } + } + false + } } /// Bounds on generics. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index dc9f5bad765fc..15ba80be1e63e 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -501,9 +501,11 @@ impl<'sess, 'src> StringReader<'sess, 'src> { (kind, self.symbol_from_to(start, end)) } rustc_lexer::LiteralKind::Float { base, empty_exponent } => { + let mut kind = token::Float; if empty_exponent { let span = self.mk_sp(start, self.pos); - self.dcx().emit_err(errors::EmptyExponentFloat { span }); + let guar = self.dcx().emit_err(errors::EmptyExponentFloat { span }); + kind = token::Err(guar); } let base = match base { Base::Hexadecimal => Some("hexadecimal"), @@ -513,9 +515,11 @@ impl<'sess, 'src> StringReader<'sess, 'src> { }; if let Some(base) = base { let span = self.mk_sp(start, end); - self.dcx().emit_err(errors::FloatLiteralUnsupportedBase { span, base }); + let guar = + self.dcx().emit_err(errors::FloatLiteralUnsupportedBase { span, base }); + kind = token::Err(guar) } - (token::Float, self.symbol_from_to(start, end)) + (kind, self.symbol_from_to(start, end)) } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a678194372e9b..d8587f1340a1a 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -971,11 +971,17 @@ impl<'a> Parser<'a> { let after_where_clause = self.parse_where_clause()?; - let where_clauses = ( - TyAliasWhereClause(before_where_clause.has_where_token, before_where_clause.span), - TyAliasWhereClause(after_where_clause.has_where_token, after_where_clause.span), - ); - let where_predicates_split = before_where_clause.predicates.len(); + let where_clauses = TyAliasWhereClauses { + before: TyAliasWhereClause { + has_where_token: before_where_clause.has_where_token, + span: before_where_clause.span, + }, + after: TyAliasWhereClause { + has_where_token: after_where_clause.has_where_token, + span: after_where_clause.span, + }, + split: before_where_clause.predicates.len(), + }; let mut predicates = before_where_clause.predicates; predicates.extend(after_where_clause.predicates); let where_clause = WhereClause { @@ -994,7 +1000,6 @@ impl<'a> Parser<'a> { defaultness, generics, where_clauses, - where_predicates_split, bounds, ty, })), diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 483986969d167..b1f910b947a93 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -940,7 +940,7 @@ impl ConstructorSet { } ConstructorSet::Variants { variants, non_exhaustive } => { let mut seen_set = index::IdxSet::new_empty(variants.len()); - for idx in seen.iter().map(|c| c.as_variant().unwrap()) { + for idx in seen.iter().filter_map(|c| c.as_variant()) { seen_set.insert(idx); } let mut skipped_a_hidden_variant = false; @@ -969,7 +969,7 @@ impl ConstructorSet { ConstructorSet::Bool => { let mut seen_false = false; let mut seen_true = false; - for b in seen.iter().map(|ctor| ctor.as_bool().unwrap()) { + for b in seen.iter().filter_map(|ctor| ctor.as_bool()) { if b { seen_true = true; } else { @@ -989,7 +989,7 @@ impl ConstructorSet { } ConstructorSet::Integers { range_1, range_2 } => { let seen_ranges: Vec<_> = - seen.iter().map(|ctor| *ctor.as_int_range().unwrap()).collect(); + seen.iter().filter_map(|ctor| ctor.as_int_range()).copied().collect(); for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) { match seen { Presence::Unseen => missing.push(IntRange(splitted_range)), @@ -1006,7 +1006,7 @@ impl ConstructorSet { } } ConstructorSet::Slice { array_len, subtype_is_empty } => { - let seen_slices = seen.iter().map(|c| c.as_slice().unwrap()); + let seen_slices = seen.iter().filter_map(|c| c.as_slice()); let base_slice = Slice::new(*array_len, VarLen(0, 0)); for (seen, splitted_slice) in base_slice.split(seen_slices) { let ctor = Slice(splitted_slice); diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index c35bab5ef6657..2d1355af09358 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -559,6 +559,21 @@ impl VecDeque { pub fn with_capacity(capacity: usize) -> VecDeque { Self::with_capacity_in(capacity, Global) } + + /// Creates an empty deque with space for at least `capacity` elements. + /// + /// # Examples + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque = VecDeque::with_capacity(10); + /// ``` + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result, TryReserveError> { + Ok(VecDeque { head: 0, len: 0, buf: RawVec::try_with_capacity_in(capacity, Global)? }) + } } impl VecDeque { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 45e93feb6c5b3..b1aa67f4d5148 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -162,6 +162,7 @@ #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] +#![feature(try_with_capacity)] #![feature(tuple_trait)] #![feature(unchecked_math)] #![feature(unicode_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index dd8d6f6c7e634..5e37de18c954f 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -17,10 +17,19 @@ use crate::collections::TryReserveErrorKind::*; #[cfg(test)] mod tests; +// One central function responsible for reporting capacity overflows. This'll +// ensure that the code generation related to these panics is minimal as there's +// only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +fn capacity_overflow() -> ! { + panic!("capacity overflow"); +} + enum AllocInit { /// The contents of the new memory are uninitialized. Uninitialized, + #[cfg(not(no_global_oom_handling))] /// The new memory is guaranteed to be zeroed. Zeroed, } @@ -93,6 +102,8 @@ impl RawVec { /// zero-sized. Note that if `T` is zero-sized this means you will /// *not* get a `RawVec` with the requested capacity. /// + /// Non-fallible version of `try_with_capacity` + /// /// # Panics /// /// Panics if the requested capacity exceeds `isize::MAX` bytes. @@ -104,7 +115,7 @@ impl RawVec { #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> Self { - Self::with_capacity_in(capacity, Global) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global)) } /// Like `with_capacity`, but guarantees the buffer is zeroed. @@ -142,7 +153,14 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)) + } + + /// Like `try_with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[inline] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) } /// Like `with_capacity_zeroed`, but parameterized over the choice @@ -150,7 +168,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, AllocInit::Zeroed, alloc) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc)) } /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. @@ -179,35 +197,41 @@ impl RawVec { } } - #[cfg(not(no_global_oom_handling))] - fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { + fn try_allocate_in( + capacity: usize, + init: AllocInit, + alloc: A, + ) -> Result { // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if T::IS_ZST || capacity == 0 { - Self::new_in(alloc) + Ok(Self::new_in(alloc)) } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match Layout::array::(capacity) { Ok(layout) => layout, - Err(_) => capacity_overflow(), + Err(_) => return Err(CapacityOverflow.into()), }; - match alloc_guard(layout.size()) { - Ok(_) => {} - Err(_) => capacity_overflow(), + + if let Err(err) = alloc_guard(layout.size()) { + return Err(err); } + let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), + #[cfg(not(no_global_oom_handling))] AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, - Err(_) => handle_alloc_error(layout), + Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()), }; // Allocators currently return a `NonNull<[u8]>` whose length // matches the size requested. If that ever changes, the capacity // here should change to `ptr.len() / mem::size_of::()`. - Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc } + Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }) } } @@ -537,11 +561,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { // Central function for reserve error handling. #[cfg(not(no_global_oom_handling))] #[inline] -fn handle_reserve(result: Result<(), TryReserveError>) { +fn handle_reserve(result: Result) -> T { match result.map_err(|e| e.kind()) { + Ok(res) => res, Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } } } @@ -561,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { Ok(()) } } - -// One central function responsible for reporting capacity overflows. This'll -// ensure that the code generation related to these panics is minimal as there's -// only one location which panics rather than a bunch throughout the module. -#[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -fn capacity_overflow() -> ! { - panic!("capacity overflow"); -} diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index f8cada01c0309..4194be530612d 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -105,13 +105,14 @@ fn zst() { let v: RawVec = RawVec::with_capacity_in(100, Global); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(0, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(100, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let mut v: RawVec = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global); + let mut v: RawVec = + RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); // Check all these operations work as expected with zero-sized elements. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 1d3c04f7807ab..a78cb872c9da1 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -492,6 +492,19 @@ impl String { String { vec: Vec::with_capacity(capacity) } } + /// Creates a new empty `String` with at least the specified capacity. + /// + /// # Errors + /// + /// Returns [`Err`] if the capacity exceeds `isize::MAX` bytes, + /// or if the memory allocator reports failure. + /// + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result { + Ok(String { vec: Vec::try_with_capacity(capacity)? }) + } + // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is // required for this method definition, is not available. Since we don't // require this method for testing purposes, I'll just stub it diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7bd19875584a3..4b8b095c752f7 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -481,6 +481,22 @@ impl Vec { Self::with_capacity_in(capacity, Global) } + /// Constructs a new, empty `Vec` with at least the specified capacity. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// # Errors + /// + /// Returns an error if the capacity exceeds `isize::MAX` _bytes_, + /// or if the allocator reports allocation failure. + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + /// Creates a `Vec` directly from a pointer, a length, and a capacity. /// /// # Safety @@ -672,6 +688,24 @@ impl Vec { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } + /// Constructs a new, empty `Vec` with at least the specified capacity + /// with the provided allocator. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// # Errors + /// + /// Returns an error if the capacity exceeds `isize::MAX` _bytes_, + /// or if the allocator reports allocation failure. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 }) + } + /// Creates a `Vec` directly from a pointer, a length, a capacity, /// and an allocator. /// diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index c4e89a58a05ac..e4e1a02fd8325 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(pattern)] #![feature(trusted_len)] #![feature(try_reserve_kind)] +#![feature(try_with_capacity)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] #![feature(binary_heap_into_iter_sorted)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 711e4eef2e724..e20ceae87b0d5 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -723,6 +723,17 @@ fn test_reserve_exact() { assert!(s.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let string = String::try_with_capacity(1000).unwrap(); + assert_eq!(0, string.len()); + assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize); + + assert!(String::try_with_capacity(usize::MAX).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 15ee4d6520523..aa95b4e977081 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1694,6 +1694,18 @@ fn test_reserve_exact() { assert!(v.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let mut vec: Vec = Vec::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + assert!(vec.spare_capacity_mut().len() >= 5); + + assert!(Vec::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index eda2f8bb812b5..cea5de4dd5984 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1182,6 +1182,17 @@ fn test_reserve_exact_2() { assert!(v.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let vec: VecDeque = VecDeque::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + + assert!(VecDeque::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 261b570dee74f..455de6d98bae6 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -11,8 +11,9 @@ use crate::fs::File; use crate::io::{ self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte, }; +use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantMutex, ReentrantMutexGuard}; +use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard}; use crate::sys::stdio; type LocalStream = Arc>>; @@ -545,7 +546,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: &'static ReentrantMutex>>, + inner: &'static ReentrantLock>>, } /// A locked reference to the [`Stdout`] handle. @@ -567,10 +568,10 @@ pub struct Stdout { #[must_use = "if unused stdout will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>, + inner: ReentrantLockGuard<'a, RefCell>>, } -static STDOUT: OnceLock>>> = OnceLock::new(); +static STDOUT: OnceLock>>> = OnceLock::new(); /// Constructs a new handle to the standard output of the current process. /// @@ -624,7 +625,7 @@ static STDOUT: OnceLock>>> = OnceLo pub fn stdout() -> Stdout { Stdout { inner: STDOUT - .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))), + .get_or_init(|| ReentrantLock::new(RefCell::new(LineWriter::new(stdout_raw())))), } } @@ -635,7 +636,7 @@ pub fn cleanup() { let mut initialized = false; let stdout = STDOUT.get_or_init(|| { initialized = true; - ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) + ReentrantLock::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) }); if !initialized { @@ -678,6 +679,12 @@ impl Stdout { } } +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Stdout {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl RefUnwindSafe for Stdout {} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stdout { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -737,6 +744,12 @@ impl Write for &Stdout { } } +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for StdoutLock<'_> {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl RefUnwindSafe for StdoutLock<'_> {} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -786,7 +799,7 @@ impl fmt::Debug for StdoutLock<'_> { /// standard library or via raw Windows API calls, will fail. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: &'static ReentrantMutex>, + inner: &'static ReentrantLock>, } /// A locked reference to the [`Stderr`] handle. @@ -808,7 +821,7 @@ pub struct Stderr { #[must_use = "if unused stderr will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>, + inner: ReentrantLockGuard<'a, RefCell>, } /// Constructs a new handle to the standard error of the current process. @@ -862,8 +875,8 @@ pub fn stderr() -> Stderr { // Note that unlike `stdout()` we don't use `at_exit` here to register a // destructor. Stderr is not buffered, so there's no need to run a // destructor for flushing the buffer - static INSTANCE: ReentrantMutex> = - ReentrantMutex::new(RefCell::new(stderr_raw())); + static INSTANCE: ReentrantLock> = + ReentrantLock::new(RefCell::new(stderr_raw())); Stderr { inner: &INSTANCE } } @@ -898,6 +911,12 @@ impl Stderr { } } +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for Stderr {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl RefUnwindSafe for Stderr {} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Stderr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -957,6 +976,12 @@ impl Write for &Stderr { } } +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl UnwindSafe for StderrLock<'_> {} + +#[stable(feature = "catch_unwind", since = "1.9.0")] +impl RefUnwindSafe for StderrLock<'_> {} + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index ca62179e95b66..e8c35bd48a70b 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -184,7 +184,8 @@ pub use self::lazy_lock::LazyLock; #[stable(feature = "once_cell", since = "1.70.0")] pub use self::once_lock::OnceLock; -pub(crate) use self::remutex::{ReentrantMutex, ReentrantMutexGuard}; +#[unstable(feature = "reentrant_lock", issue = "121440")] +pub use self::reentrant_lock::{ReentrantLock, ReentrantLockGuard}; pub mod mpsc; @@ -196,5 +197,5 @@ mod mutex; pub(crate) mod once; mod once_lock; mod poison; -mod remutex; +mod reentrant_lock; mod rwlock; diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs new file mode 100644 index 0000000000000..9a44998ebf644 --- /dev/null +++ b/library/std/src/sync/reentrant_lock.rs @@ -0,0 +1,320 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +use crate::cell::UnsafeCell; +use crate::fmt; +use crate::ops::Deref; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; +use crate::sys::locks as sys; + +/// A re-entrant mutual exclusion lock +/// +/// This lock will block *other* threads waiting for the lock to become +/// available. The thread which has already locked the mutex can lock it +/// multiple times without blocking, preventing a common source of deadlocks. +/// +/// # Examples +/// +/// Allow recursively calling a function needing synchronization from within +/// a callback (this is how [`StdoutLock`](crate::io::StdoutLock) is currently +/// implemented): +/// +/// ``` +/// #![feature(reentrant_lock)] +/// +/// use std::cell::RefCell; +/// use std::sync::ReentrantLock; +/// +/// pub struct Log { +/// data: RefCell, +/// } +/// +/// impl Log { +/// pub fn append(&self, msg: &str) { +/// self.data.borrow_mut().push_str(msg); +/// } +/// } +/// +/// static LOG: ReentrantLock = ReentrantLock::new(Log { data: RefCell::new(String::new()) }); +/// +/// pub fn with_log(f: impl FnOnce(&Log) -> R) -> R { +/// let log = LOG.lock(); +/// f(&*log) +/// } +/// +/// with_log(|log| { +/// log.append("Hello"); +/// with_log(|log| log.append(" there!")); +/// }); +/// ``` +/// +// # Implementation details +// +// The 'owner' field tracks which thread has locked the mutex. +// +// We use current_thread_unique_ptr() as the thread identifier, +// which is just the address of a thread local variable. +// +// If `owner` is set to the identifier of the current thread, +// we assume the mutex is already locked and instead of locking it again, +// we increment `lock_count`. +// +// When unlocking, we decrement `lock_count`, and only unlock the mutex when +// it reaches zero. +// +// `lock_count` is protected by the mutex and only accessed by the thread that has +// locked the mutex, so needs no synchronization. +// +// `owner` can be checked by other threads that want to see if they already +// hold the lock, so needs to be atomic. If it compares equal, we're on the +// same thread that holds the mutex and memory access can use relaxed ordering +// since we're not dealing with multiple threads. If it's not equal, +// synchronization is left to the mutex, making relaxed memory ordering for +// the `owner` field fine in all cases. +#[unstable(feature = "reentrant_lock", issue = "121440")] +pub struct ReentrantLock { + mutex: sys::Mutex, + owner: AtomicUsize, + lock_count: UnsafeCell, + data: T, +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +unsafe impl Send for ReentrantLock {} +#[unstable(feature = "reentrant_lock", issue = "121440")] +unsafe impl Sync for ReentrantLock {} + +// Because of the `UnsafeCell`, these traits are not implemented automatically +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl UnwindSafe for ReentrantLock {} +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl RefUnwindSafe for ReentrantLock {} + +/// An RAII implementation of a "scoped lock" of a re-entrant lock. When this +/// structure is dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// [`Deref`] implementation. +/// +/// This structure is created by the [`lock`](ReentrantLock::lock) method on +/// [`ReentrantLock`]. +/// +/// # Mutability +/// +/// Unlike [`MutexGuard`](super::MutexGuard), `ReentrantLockGuard` does not +/// implement [`DerefMut`](crate::ops::DerefMut), because implementation of +/// the trait would violate Rust’s reference aliasing rules. Use interior +/// mutability (usually [`RefCell`](crate::cell::RefCell)) in order to mutate +/// the guarded data. +#[must_use = "if unused the ReentrantLock will immediately unlock"] +#[unstable(feature = "reentrant_lock", issue = "121440")] +pub struct ReentrantLockGuard<'a, T: ?Sized + 'a> { + lock: &'a ReentrantLock, +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl !Send for ReentrantLockGuard<'_, T> {} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl ReentrantLock { + /// Creates a new re-entrant lock in an unlocked state ready for use. + /// + /// # Examples + /// + /// ``` + /// #![feature(reentrant_lock)] + /// use std::sync::ReentrantLock; + /// + /// let lock = ReentrantLock::new(0); + /// ``` + pub const fn new(t: T) -> ReentrantLock { + ReentrantLock { + mutex: sys::Mutex::new(), + owner: AtomicUsize::new(0), + lock_count: UnsafeCell::new(0), + data: t, + } + } + + /// Consumes this lock, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// #![feature(reentrant_lock)] + /// + /// use std::sync::ReentrantLock; + /// + /// let lock = ReentrantLock::new(0); + /// assert_eq!(lock.into_inner(), 0); + /// ``` + pub fn into_inner(self) -> T { + self.data + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl ReentrantLock { + /// Acquires the lock, blocking the current thread until it is able to do + /// so. + /// + /// This function will block the caller until it is available to acquire + /// the lock. Upon returning, the thread is the only thread with the lock + /// held. When the thread calling this method already holds the lock, the + /// call succeeds without blocking. + /// + /// # Examples + /// + /// ``` + /// #![feature(reentrant_lock)] + /// use std::cell::Cell; + /// use std::sync::{Arc, ReentrantLock}; + /// use std::thread; + /// + /// let lock = Arc::new(ReentrantLock::new(Cell::new(0))); + /// let c_lock = Arc::clone(&lock); + /// + /// thread::spawn(move || { + /// c_lock.lock().set(10); + /// }).join().expect("thread::spawn failed"); + /// assert_eq!(lock.lock().get(), 10); + /// ``` + pub fn lock(&self) -> ReentrantLockGuard<'_, T> { + let this_thread = current_thread_unique_ptr(); + // Safety: We only touch lock_count when we own the lock. + unsafe { + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count().expect("lock count overflow in reentrant mutex"); + } else { + self.mutex.lock(); + self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); + *self.lock_count.get() = 1; + } + } + ReentrantLockGuard { lock: self } + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `ReentrantLock` mutably, no actual locking + /// needs to take place -- the mutable borrow statically guarantees no locks + /// exist. + /// + /// # Examples + /// + /// ``` + /// #![feature(reentrant_lock)] + /// use std::sync::ReentrantLock; + /// + /// let mut lock = ReentrantLock::new(0); + /// *lock.get_mut() = 10; + /// assert_eq!(*lock.lock(), 10); + /// ``` + pub fn get_mut(&mut self) -> &mut T { + &mut self.data + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `None` is returned. + /// Otherwise, an RAII guard is returned. + /// + /// This function does not block. + pub(crate) fn try_lock(&self) -> Option> { + let this_thread = current_thread_unique_ptr(); + // Safety: We only touch lock_count when we own the lock. + unsafe { + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count()?; + Some(ReentrantLockGuard { lock: self }) + } else if self.mutex.try_lock() { + self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); + *self.lock_count.get() = 1; + Some(ReentrantLockGuard { lock: self }) + } else { + None + } + } + } + + unsafe fn increment_lock_count(&self) -> Option<()> { + *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; + Some(()) + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl fmt::Debug for ReentrantLock { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("ReentrantLock"); + match self.try_lock() { + Some(v) => d.field("data", &&*v), + None => d.field("data", &format_args!("")), + }; + d.finish_non_exhaustive() + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl Default for ReentrantLock { + fn default() -> Self { + Self::new(T::default()) + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl From for ReentrantLock { + fn from(t: T) -> Self { + Self::new(t) + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl Deref for ReentrantLockGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + &self.lock.data + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl fmt::Debug for ReentrantLockGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl fmt::Display for ReentrantLockGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "reentrant_lock", issue = "121440")] +impl Drop for ReentrantLockGuard<'_, T> { + #[inline] + fn drop(&mut self) { + // Safety: We own the lock. + unsafe { + *self.lock.lock_count.get() -= 1; + if *self.lock.lock_count.get() == 0 { + self.lock.owner.store(0, Relaxed); + self.lock.mutex.unlock(); + } + } + } +} + +/// Get an address that is unique per running thread. +/// +/// This can be used as a non-null usize-sized ID. +pub(crate) fn current_thread_unique_ptr() -> usize { + // Use a non-drop type to make sure it's still available during thread destruction. + thread_local! { static X: u8 = const { 0 } } + X.with(|x| <*const _>::addr(x)) +} diff --git a/library/std/src/sync/remutex/tests.rs b/library/std/src/sync/reentrant_lock/tests.rs similarity index 53% rename from library/std/src/sync/remutex/tests.rs rename to library/std/src/sync/reentrant_lock/tests.rs index fc553081d4227..d4c1d440c6109 100644 --- a/library/std/src/sync/remutex/tests.rs +++ b/library/std/src/sync/reentrant_lock/tests.rs @@ -1,17 +1,17 @@ -use super::{ReentrantMutex, ReentrantMutexGuard}; +use super::{ReentrantLock, ReentrantLockGuard}; use crate::cell::RefCell; use crate::sync::Arc; use crate::thread; #[test] fn smoke() { - let m = ReentrantMutex::new(()); + let l = ReentrantLock::new(()); { - let a = m.lock(); + let a = l.lock(); { - let b = m.lock(); + let b = l.lock(); { - let c = m.lock(); + let c = l.lock(); assert_eq!(*c, ()); } assert_eq!(*b, ()); @@ -22,15 +22,15 @@ fn smoke() { #[test] fn is_mutex() { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let m2 = m.clone(); - let lock = m.lock(); + let l = Arc::new(ReentrantLock::new(RefCell::new(0))); + let l2 = l.clone(); + let lock = l.lock(); let child = thread::spawn(move || { - let lock = m2.lock(); + let lock = l2.lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.lock(); + let lock = l.lock(); *lock.borrow_mut() += i; } drop(lock); @@ -39,20 +39,20 @@ fn is_mutex() { #[test] fn trylock_works() { - let m = Arc::new(ReentrantMutex::new(())); - let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); + let l = Arc::new(ReentrantLock::new(())); + let l2 = l.clone(); + let _lock = l.try_lock(); + let _lock2 = l.try_lock(); thread::spawn(move || { - let lock = m2.try_lock(); + let lock = l2.try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.try_lock(); + let _lock3 = l.try_lock(); } -pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); +pub struct Answer<'a>(pub ReentrantLockGuard<'a, RefCell>); impl Drop for Answer<'_> { fn drop(&mut self) { *self.0.borrow_mut() = 42; diff --git a/library/std/src/sync/remutex.rs b/library/std/src/sync/remutex.rs deleted file mode 100644 index 0ced48d10b7c6..0000000000000 --- a/library/std/src/sync/remutex.rs +++ /dev/null @@ -1,178 +0,0 @@ -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -use crate::cell::UnsafeCell; -use crate::ops::Deref; -use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -use crate::sys::locks as sys; - -/// A reentrant mutual exclusion -/// -/// This mutex will block *other* threads waiting for the lock to become -/// available. The thread which has already locked the mutex can lock it -/// multiple times without blocking, preventing a common source of deadlocks. -/// -/// This is used by stdout().lock() and friends. -/// -/// ## Implementation details -/// -/// The 'owner' field tracks which thread has locked the mutex. -/// -/// We use current_thread_unique_ptr() as the thread identifier, -/// which is just the address of a thread local variable. -/// -/// If `owner` is set to the identifier of the current thread, -/// we assume the mutex is already locked and instead of locking it again, -/// we increment `lock_count`. -/// -/// When unlocking, we decrement `lock_count`, and only unlock the mutex when -/// it reaches zero. -/// -/// `lock_count` is protected by the mutex and only accessed by the thread that has -/// locked the mutex, so needs no synchronization. -/// -/// `owner` can be checked by other threads that want to see if they already -/// hold the lock, so needs to be atomic. If it compares equal, we're on the -/// same thread that holds the mutex and memory access can use relaxed ordering -/// since we're not dealing with multiple threads. If it's not equal, -/// synchronization is left to the mutex, making relaxed memory ordering for -/// the `owner` field fine in all cases. -pub struct ReentrantMutex { - mutex: sys::Mutex, - owner: AtomicUsize, - lock_count: UnsafeCell, - data: T, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl UnwindSafe for ReentrantMutex {} -impl RefUnwindSafe for ReentrantMutex {} - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// Deref implementation. -/// -/// # Mutability -/// -/// Unlike `MutexGuard`, `ReentrantMutexGuard` does not implement `DerefMut`, -/// because implementation of the trait would violate Rust’s reference aliasing -/// rules. Use interior mutability (usually `RefCell`) in order to mutate the -/// guarded data. -#[must_use = "if unused the ReentrantMutex will immediately unlock"] -pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: &'a ReentrantMutex, -} - -impl !Send for ReentrantMutexGuard<'_, T> {} - -impl ReentrantMutex { - /// Creates a new reentrant mutex in an unlocked state. - pub const fn new(t: T) -> ReentrantMutex { - ReentrantMutex { - mutex: sys::Mutex::new(), - owner: AtomicUsize::new(0), - lock_count: UnsafeCell::new(0), - data: t, - } - } - - /// Acquires a mutex, blocking the current thread until it is able to do so. - /// - /// This function will block the caller until it is available to acquire the mutex. - /// Upon returning, the thread is the only thread with the mutex held. When the thread - /// calling this method already holds the lock, the call shall succeed without - /// blocking. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { - let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock. - unsafe { - if self.owner.load(Relaxed) == this_thread { - self.increment_lock_count(); - } else { - self.mutex.lock(); - self.owner.store(this_thread, Relaxed); - debug_assert_eq!(*self.lock_count.get(), 0); - *self.lock_count.get() = 1; - } - } - ReentrantMutexGuard { lock: self } - } - - /// Attempts to acquire this lock. - /// - /// If the lock could not be acquired at this time, then `Err` is returned. - /// Otherwise, an RAII guard is returned. - /// - /// This function does not block. - /// - /// # Errors - /// - /// If another user of this mutex panicked while holding the mutex, then - /// this call will return failure if the mutex would otherwise be - /// acquired. - pub fn try_lock(&self) -> Option> { - let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock. - unsafe { - if self.owner.load(Relaxed) == this_thread { - self.increment_lock_count(); - Some(ReentrantMutexGuard { lock: self }) - } else if self.mutex.try_lock() { - self.owner.store(this_thread, Relaxed); - debug_assert_eq!(*self.lock_count.get(), 0); - *self.lock_count.get() = 1; - Some(ReentrantMutexGuard { lock: self }) - } else { - None - } - } - } - - unsafe fn increment_lock_count(&self) { - *self.lock_count.get() = (*self.lock_count.get()) - .checked_add(1) - .expect("lock count overflow in reentrant mutex"); - } -} - -impl Deref for ReentrantMutexGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - &self.lock.data - } -} - -impl Drop for ReentrantMutexGuard<'_, T> { - #[inline] - fn drop(&mut self) { - // Safety: We own the lock. - unsafe { - *self.lock.lock_count.get() -= 1; - if *self.lock.lock_count.get() == 0 { - self.lock.owner.store(0, Relaxed); - self.lock.mutex.unlock(); - } - } - } -} - -/// Get an address that is unique per running thread. -/// -/// This can be used as a non-null usize-sized ID. -pub fn current_thread_unique_ptr() -> usize { - // Use a non-drop type to make sure it's still available during thread destruction. - thread_local! { static X: u8 = const { 0 } } - X.with(|x| <*const _>::addr(x)) -} diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 1cdc792a819a8..aa5998876d9ab 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -136,6 +136,7 @@ fn can_merge(class1: Option, class2: Option, text: &str) -> bool { match (class1, class2) { (Some(c1), Some(c2)) => c1.is_equal_to(c2), (Some(Class::Ident(_)), None) | (None, Some(Class::Ident(_))) => true, + (Some(Class::Macro(_)), _) => false, (Some(_), None) | (None, Some(_)) => text.trim().is_empty(), (None, None) => true, } diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index aa735e81597c7..773afd5c2cc30 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -32,7 +32,7 @@ } } -macro_rules! bar { +macro_rules! bar { ($foo:tt) => {}; } diff --git a/src/tools/clippy/tests/ui/crashes/ice-10912.rs b/src/tools/clippy/tests/ui/crashes/ice-10912.rs index 8dfce19422171..1d689e1d0082d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10912.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-10912.rs @@ -2,7 +2,5 @@ //@no-rustfix fn f2() -> impl Sized { && 3.14159265358979323846E } //~^ ERROR: expected at least one digit in exponent -//~| ERROR: long literal lacking separators -//~| NOTE: `-D clippy::unreadable-literal` implied by `-D warnings` fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10912.stderr b/src/tools/clippy/tests/ui/crashes/ice-10912.stderr index cc80354c7c626..c697e54679f96 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10912.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-10912.stderr @@ -4,14 +4,5 @@ error: expected at least one digit in exponent LL | fn f2() -> impl Sized { && 3.14159265358979323846E } | ^^^^^^^^^^^^^^^^^^^^^^^ -error: long literal lacking separators - --> tests/ui/crashes/ice-10912.rs:3:28 - | -LL | fn f2() -> impl Sized { && 3.14159265358979323846E } - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider: `3.141_592_653_589_793_238_46` - | - = note: `-D clippy::unreadable-literal` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unreadable_literal)]` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index b57be8c10549e..f6f51fbd8eaf9 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1651,8 +1651,7 @@ struct TyAliasRewriteInfo<'c, 'g>( &'c RewriteContext<'c>, Indent, &'g ast::Generics, - (ast::TyAliasWhereClause, ast::TyAliasWhereClause), - usize, + ast::TyAliasWhereClauses, symbol::Ident, Span, ); @@ -1672,7 +1671,6 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( ref bounds, ref ty, where_clauses, - where_predicates_split, } = *ty_alias_kind; let ty_opt = ty.as_ref(); let (ident, vis) = match visitor_kind { @@ -1680,15 +1678,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis), ForeignItem(i) => (i.ident, &i.vis), }; - let rw_info = &TyAliasRewriteInfo( - context, - indent, - generics, - where_clauses, - where_predicates_split, - ident, - span, - ); + let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span); let op_ty = opaque_ty(ty); // Type Aliases are formatted slightly differently depending on the context // in which they appear, whether they are opaque, and whether they are associated. @@ -1724,19 +1714,11 @@ fn rewrite_ty( vis: &ast::Visibility, ) -> Option { let mut result = String::with_capacity(128); - let TyAliasRewriteInfo( - context, - indent, - generics, - where_clauses, - where_predicates_split, - ident, - span, - ) = *rw_info; + let TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span) = *rw_info; let (before_where_predicates, after_where_predicates) = generics .where_clause .predicates - .split_at(where_predicates_split); + .split_at(where_clauses.split); if !after_where_predicates.is_empty() { return None; } @@ -1771,7 +1753,7 @@ fn rewrite_ty( let where_clause_str = rewrite_where_clause( context, before_where_predicates, - where_clauses.0.1, + where_clauses.before.span, context.config.brace_style(), Shape::legacy(where_budget, indent), false, @@ -1795,7 +1777,7 @@ fn rewrite_ty( let comment_span = context .snippet_provider .opt_span_before(span, "=") - .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo)); + .map(|op_lo| mk_sp(where_clauses.before.span.hi(), op_lo)); let lhs = match comment_span { Some(comment_span) diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs new file mode 100644 index 0000000000000..9d2d8481ce048 --- /dev/null +++ b/tests/codegen/vec-with-capacity.rs @@ -0,0 +1,35 @@ +// compile-flags: -O +// ignore-debug +// (with debug assertions turned on, `assert_unchecked` generates a real assertion) + +#![crate_type = "lib"] +#![feature(try_with_capacity)] + +// CHECK-LABEL: @with_capacity_does_not_grow1 +#[no_mangle] +pub fn with_capacity_does_not_grow1() -> Vec { + let v = Vec::with_capacity(1234); + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + v +} + +// CHECK-LABEL: @try_with_capacity_does_not_grow2 +#[no_mangle] +pub fn try_with_capacity_does_not_grow2() -> Option>> { + let v = Vec::try_with_capacity(1234).ok()?; + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}handle_alloc_error + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Some(v) +} diff --git a/tests/rustdoc/source-code-highlight.rs b/tests/rustdoc/source-code-highlight.rs new file mode 100644 index 0000000000000..0a1be791ec2d8 --- /dev/null +++ b/tests/rustdoc/source-code-highlight.rs @@ -0,0 +1,29 @@ +// We need this option to be enabled for the `foo` macro declaration to ensure +// that the link on the ident is not including whitespace characters. + +//@ compile-flags: -Zunstable-options --generate-link-to-definition +#![crate_name = "foo"] + +// @has 'src/foo/source-code-highlight.rs.html' + +// @hasraw - 'foo' +#[macro_export] +macro_rules! foo { + () => {} +} + +// @hasraw - 'foo!' +foo! {} + +// @hasraw - 'f' +#[rustfmt::skip] +pub fn f () {} +// @hasraw - 'Bar' +// @hasraw - 'Bar' +// @hasraw - 'u32' +#[rustfmt::skip] +pub struct Bar ( u32 ); +// @hasraw - 'Foo' +pub enum Foo { + A, +} diff --git a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs index 66d562d2eb519..5c2c3b8ec61d5 100644 --- a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs +++ b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs @@ -1,6 +1,5 @@ const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² //~^ ERROR expected at least one digit in exponent //~| ERROR unknown start of token: \u{2212} -//~| ERROR cannot subtract `{integer}` from `{float}` fn main() {} diff --git a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index 44bdbb93ff51c..4b3d429c7509a 100644 --- a/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/tests/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -15,24 +15,5 @@ help: Unicode character '−' (Minus Sign) looks like '-' (Minus/Hyphen), but it LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e-11; // m³⋅kg⁻¹⋅s⁻² | ~ -error[E0277]: cannot subtract `{integer}` from `{float}` - --> $DIR/issue-49746-unicode-confusable-in-float-literal-expt.rs:1:53 - | -LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² - | ^ no implementation for `{float} - {integer}` - | - = help: the trait `Sub<{integer}>` is not implemented for `{float}` - = help: the following other types implement trait `Sub`: - - > - - > - - > - - > - and 48 others - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 5c552411da7f3..ec0ce18c3dfa7 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:571:5: +thread 'main' panicked at library/alloc/src/raw_vec.rs:26:5: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs index 7f3817b326adc..5e3d21eb26ad7 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.rs @@ -10,7 +10,7 @@ pub trait MessageListenersInterface { impl<'a> MessageListenersInterface for MessageListeners<'a> { fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - //~^ ERROR cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements + //~^ ERROR in type `&'a MessageListeners<'_>`, reference has a longer lifetime than the data it references self } } diff --git a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr index 6a412eb5e4bee..e0cf15d0d1f33 100644 --- a/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr +++ b/tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr @@ -1,27 +1,15 @@ -error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'b in generic type due to conflicting requirements +error[E0491]: in type `&'a MessageListeners<'_>`, reference has a longer lifetime than the data it references --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: first, the lifetime cannot outlive the lifetime `'c` as defined here... - --> $DIR/impl-implied-bounds-compatibility.rs:12:5 - | -LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so that the method type is compatible with trait - --> $DIR/impl-implied-bounds-compatibility.rs:12:5 - | -LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `fn(&'c MessageListeners<'_>) -> &'c MessageListeners<'c>` - found `fn(&MessageListeners<'_>) -> &'a MessageListeners<'_>` -note: but, the lifetime must be valid for the lifetime `'a` as defined here... +note: the pointer is valid for the lifetime `'a` as defined here --> $DIR/impl-implied-bounds-compatibility.rs:11:6 | LL | impl<'a> MessageListenersInterface for MessageListeners<'a> { | ^^ -note: ...so that the reference type `&'a MessageListeners<'_>` does not outlive the data it points at +note: but the referenced data is only valid for the lifetime `'c` as defined here --> $DIR/impl-implied-bounds-compatibility.rs:12:5 | LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { @@ -29,4 +17,4 @@ LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/lazy-type-alias/leading-where-clause.fixed b/tests/ui/lazy-type-alias/leading-where-clause.fixed index 885556c1efe7f..ca0ab7b5c7dd2 100644 --- a/tests/ui/lazy-type-alias/leading-where-clause.fixed +++ b/tests/ui/lazy-type-alias/leading-where-clause.fixed @@ -2,14 +2,22 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] +#![crate_type = "lib"] // Check that we *reject* leading where-clauses on lazy type aliases. -type Alias +pub type Leading0 = T where String: From; -//~^^^ ERROR where clauses are not allowed before the type for type aliases -fn main() { - let _: Alias<&str>; -} +pub type Leading1 + += (T, U) +where + U: Copy, String: From; + +pub type EmptyLeading0 = () where; +//~^ ERROR where clauses are not allowed before the type for type aliases + +pub type EmptyLeading1 = T where T: Copy; +//~^ ERROR where clauses are not allowed before the type for type aliases diff --git a/tests/ui/lazy-type-alias/leading-where-clause.rs b/tests/ui/lazy-type-alias/leading-where-clause.rs index a0a09a2a08ee1..460f7e3a9994d 100644 --- a/tests/ui/lazy-type-alias/leading-where-clause.rs +++ b/tests/ui/lazy-type-alias/leading-where-clause.rs @@ -2,15 +2,24 @@ #![feature(lazy_type_alias)] #![allow(incomplete_features)] +#![crate_type = "lib"] // Check that we *reject* leading where-clauses on lazy type aliases. -type Alias -where +pub type Leading0 +where //~ ERROR where clauses are not allowed before the type for type aliases String: From, = T; -//~^^^ ERROR where clauses are not allowed before the type for type aliases -fn main() { - let _: Alias<&str>; -} +pub type Leading1 +where //~ ERROR where clauses are not allowed before the type for type aliases + String: From, += (T, U) +where + U: Copy; + +pub type EmptyLeading0 where = (); +//~^ ERROR where clauses are not allowed before the type for type aliases + +pub type EmptyLeading1 where = T where T: Copy; +//~^ ERROR where clauses are not allowed before the type for type aliases diff --git a/tests/ui/lazy-type-alias/leading-where-clause.stderr b/tests/ui/lazy-type-alias/leading-where-clause.stderr index 6b0613787e8bf..344c318d0ef9d 100644 --- a/tests/ui/lazy-type-alias/leading-where-clause.stderr +++ b/tests/ui/lazy-type-alias/leading-where-clause.stderr @@ -1,5 +1,5 @@ error: where clauses are not allowed before the type for type aliases - --> $DIR/leading-where-clause.rs:9:1 + --> $DIR/leading-where-clause.rs:10:1 | LL | / where LL | | String: From, @@ -12,5 +12,42 @@ LL + LL ~ = T where String: From; | -error: aborting due to 1 previous error +error: where clauses are not allowed before the type for type aliases + --> $DIR/leading-where-clause.rs:15:1 + | +LL | / where +LL | | String: From, + | |____________________^ + | + = note: see issue #89122 for more information +help: move it to the end of the type declaration + | +LL + +LL | = (T, U) +LL | where +LL ~ U: Copy, String: From; + | + +error: where clauses are not allowed before the type for type aliases + --> $DIR/leading-where-clause.rs:21:24 + | +LL | pub type EmptyLeading0 where = (); + | ^^^^^ + | + = note: see issue #89122 for more information +help: move it to the end of the type declaration + | +LL - pub type EmptyLeading0 where = (); +LL + pub type EmptyLeading0 = () where; + | + +error: where clauses are not allowed before the type for type aliases + --> $DIR/leading-where-clause.rs:24:27 + | +LL | pub type EmptyLeading1 where = T where T: Copy; + | ^^^^^ help: remove this `where` + | + = note: see issue #89122 for more information + +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/float-field.rs b/tests/ui/parser/float-field.rs index eaa7465dc4d06..59fefee26aa6f 100644 --- a/tests/ui/parser/float-field.rs +++ b/tests/ui/parser/float-field.rs @@ -3,60 +3,91 @@ struct S(u8, (u8, u8)); fn main() { let s = S(0, (0, 0)); - s.1e1; //~ ERROR no field `1e1` on type `S` - s.1.; //~ ERROR unexpected token: `;` - s.1.1; - s.1.1e1; //~ ERROR no field `1e1` on type `(u8, u8)` + { s.1e1; } //~ ERROR no field `1e1` on type `S` + + { s.1.; } //~ ERROR unexpected token: `;` + + { s.1.1; } + + { s.1.1e1; } //~ ERROR no field `1e1` on type `(u8, u8)` + { s.1e+; } //~ ERROR unexpected token: `1e+` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+` //~| ERROR expected at least one digit in exponent + { s.1e-; } //~ ERROR unexpected token: `1e-` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-` //~| ERROR expected at least one digit in exponent + { s.1e+1; } //~ ERROR unexpected token: `1e+1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+1` + { s.1e-1; } //~ ERROR unexpected token: `1e-1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-1` + { s.1.1e+1; } //~ ERROR unexpected token: `1.1e+1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e+1` + { s.1.1e-1; } //~ ERROR unexpected token: `1.1e-1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e-1` - s.0x1e1; //~ ERROR no field `0x1e1` on type `S` - s.0x1.; //~ ERROR no field `0x1` on type `S` - //~| ERROR hexadecimal float literal is not supported - //~| ERROR unexpected token: `;` - s.0x1.1; //~ ERROR no field `0x1` on type `S` - //~| ERROR hexadecimal float literal is not supported - s.0x1.1e1; //~ ERROR no field `0x1` on type `S` - //~| ERROR hexadecimal float literal is not supported + + { s.0x1e1; } //~ ERROR no field `0x1e1` on type `S` + + { s.0x1.; } //~ ERROR hexadecimal float literal is not supported + //~| ERROR unexpected token: `0x1.` + //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.` + + { s.0x1.1; } //~ ERROR hexadecimal float literal is not supported + //~| ERROR unexpected token: `0x1.1` + //~| expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1` + + { s.0x1.1e1; } //~ ERROR hexadecimal float literal is not supported + //~| ERROR unexpected token: `0x1.1e1` + //~| expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e1` + { s.0x1e+; } //~ ERROR expected expression, found `;` + { s.0x1e-; } //~ ERROR expected expression, found `;` - s.0x1e+1; //~ ERROR no field `0x1e` on type `S` - s.0x1e-1; //~ ERROR no field `0x1e` on type `S` + + { s.0x1e+1; } //~ ERROR no field `0x1e` on type `S` + + { s.0x1e-1; } //~ ERROR no field `0x1e` on type `S` + { s.0x1.1e+1; } //~ ERROR unexpected token: `0x1.1e+1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e+1` //~| ERROR hexadecimal float literal is not supported + { s.0x1.1e-1; } //~ ERROR unexpected token: `0x1.1e-1` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e-1` //~| ERROR hexadecimal float literal is not supported - s.1e1f32; //~ ERROR no field `1e1` on type `S` - //~| ERROR suffixes on a tuple index are invalid - s.1.f32; //~ ERROR no field `f32` on type `(u8, u8)` - s.1.1f32; //~ ERROR suffixes on a tuple index are invalid - s.1.1e1f32; //~ ERROR no field `1e1` on type `(u8, u8)` - //~| ERROR suffixes on a tuple index are invalid + + { s.1e1f32; } //~ ERROR no field `1e1` on type `S` + //~| ERROR suffixes on a tuple index are invalid + + { s.1.f32; } //~ ERROR no field `f32` on type `(u8, u8)` + + { s.1.1f32; } //~ ERROR suffixes on a tuple index are invalid + + { s.1.1e1f32; } //~ ERROR no field `1e1` on type `(u8, u8)` + //~| ERROR suffixes on a tuple index are invalid + { s.1e+f32; } //~ ERROR unexpected token: `1e+f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+f32` //~| ERROR expected at least one digit in exponent + { s.1e-f32; } //~ ERROR unexpected token: `1e-f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-f32` //~| ERROR expected at least one digit in exponent + { s.1e+1f32; } //~ ERROR unexpected token: `1e+1f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+1f32` + { s.1e-1f32; } //~ ERROR unexpected token: `1e-1f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-1f32` + { s.1.1e+1f32; } //~ ERROR unexpected token: `1.1e+1f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e+1f32` + { s.1.1e-1f32; } //~ ERROR unexpected token: `1.1e-1f32` //~| ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e-1f32` } diff --git a/tests/ui/parser/float-field.stderr b/tests/ui/parser/float-field.stderr index d67d270ef7b93..0cc1b0767dc74 100644 --- a/tests/ui/parser/float-field.stderr +++ b/tests/ui/parser/float-field.stderr @@ -1,349 +1,355 @@ error: expected at least one digit in exponent - --> $DIR/float-field.rs:10:9 + --> $DIR/float-field.rs:14:9 | LL | { s.1e+; } | ^^^ error: expected at least one digit in exponent - --> $DIR/float-field.rs:13:9 + --> $DIR/float-field.rs:18:9 | LL | { s.1e-; } | ^^^ error: hexadecimal float literal is not supported - --> $DIR/float-field.rs:25:7 + --> $DIR/float-field.rs:36:9 | -LL | s.0x1.; - | ^^^^ +LL | { s.0x1.; } + | ^^^^ error: hexadecimal float literal is not supported - --> $DIR/float-field.rs:28:7 + --> $DIR/float-field.rs:40:9 | -LL | s.0x1.1; - | ^^^^^ +LL | { s.0x1.1; } + | ^^^^^ error: hexadecimal float literal is not supported - --> $DIR/float-field.rs:30:7 + --> $DIR/float-field.rs:44:9 | -LL | s.0x1.1e1; - | ^^^^^^^ +LL | { s.0x1.1e1; } + | ^^^^^^^ error: hexadecimal float literal is not supported - --> $DIR/float-field.rs:36:9 + --> $DIR/float-field.rs:56:9 | LL | { s.0x1.1e+1; } | ^^^^^^^^ error: hexadecimal float literal is not supported - --> $DIR/float-field.rs:39:9 + --> $DIR/float-field.rs:60:9 | LL | { s.0x1.1e-1; } | ^^^^^^^^ error: expected at least one digit in exponent - --> $DIR/float-field.rs:48:9 + --> $DIR/float-field.rs:74:9 | LL | { s.1e+f32; } | ^^^^^^ error: expected at least one digit in exponent - --> $DIR/float-field.rs:51:9 + --> $DIR/float-field.rs:78:9 | LL | { s.1e-f32; } | ^^^^^^ error: unexpected token: `;` - --> $DIR/float-field.rs:7:9 + --> $DIR/float-field.rs:8:11 | -LL | s.1.; - | ^ +LL | { s.1.; } + | ^ error: unexpected token: `1e+` - --> $DIR/float-field.rs:10:9 + --> $DIR/float-field.rs:14:9 | LL | { s.1e+; } | ^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+` - --> $DIR/float-field.rs:10:9 + --> $DIR/float-field.rs:14:9 | LL | { s.1e+; } | ^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e-` - --> $DIR/float-field.rs:13:9 + --> $DIR/float-field.rs:18:9 | LL | { s.1e-; } | ^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-` - --> $DIR/float-field.rs:13:9 + --> $DIR/float-field.rs:18:9 | LL | { s.1e-; } | ^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e+1` - --> $DIR/float-field.rs:16:9 + --> $DIR/float-field.rs:22:9 | LL | { s.1e+1; } | ^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+1` - --> $DIR/float-field.rs:16:9 + --> $DIR/float-field.rs:22:9 | LL | { s.1e+1; } | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e-1` - --> $DIR/float-field.rs:18:9 + --> $DIR/float-field.rs:25:9 | LL | { s.1e-1; } | ^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-1` - --> $DIR/float-field.rs:18:9 + --> $DIR/float-field.rs:25:9 | LL | { s.1e-1; } | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1.1e+1` - --> $DIR/float-field.rs:20:9 + --> $DIR/float-field.rs:28:9 | LL | { s.1.1e+1; } | ^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e+1` - --> $DIR/float-field.rs:20:9 + --> $DIR/float-field.rs:28:9 | LL | { s.1.1e+1; } | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1.1e-1` - --> $DIR/float-field.rs:22:9 + --> $DIR/float-field.rs:31:9 | LL | { s.1.1e-1; } | ^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e-1` - --> $DIR/float-field.rs:22:9 + --> $DIR/float-field.rs:31:9 | LL | { s.1.1e-1; } | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator -error: unexpected token: `;` - --> $DIR/float-field.rs:25:11 +error: unexpected token: `0x1.` + --> $DIR/float-field.rs:36:9 | -LL | s.0x1.; - | ^ +LL | { s.0x1.; } + | ^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.` + --> $DIR/float-field.rs:36:9 + | +LL | { s.0x1.; } + | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: unexpected token: `0x1.1` + --> $DIR/float-field.rs:40:9 + | +LL | { s.0x1.1; } + | ^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1` + --> $DIR/float-field.rs:40:9 + | +LL | { s.0x1.1; } + | ^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator + +error: unexpected token: `0x1.1e1` + --> $DIR/float-field.rs:44:9 + | +LL | { s.0x1.1e1; } + | ^^^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e1` + --> $DIR/float-field.rs:44:9 + | +LL | { s.0x1.1e1; } + | ^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected expression, found `;` - --> $DIR/float-field.rs:32:14 + --> $DIR/float-field.rs:48:14 | LL | { s.0x1e+; } | ^ expected expression error: expected expression, found `;` - --> $DIR/float-field.rs:33:14 + --> $DIR/float-field.rs:50:14 | LL | { s.0x1e-; } | ^ expected expression error: unexpected token: `0x1.1e+1` - --> $DIR/float-field.rs:36:9 + --> $DIR/float-field.rs:56:9 | LL | { s.0x1.1e+1; } | ^^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e+1` - --> $DIR/float-field.rs:36:9 + --> $DIR/float-field.rs:56:9 | LL | { s.0x1.1e+1; } | ^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `0x1.1e-1` - --> $DIR/float-field.rs:39:9 + --> $DIR/float-field.rs:60:9 | LL | { s.0x1.1e-1; } | ^^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `0x1.1e-1` - --> $DIR/float-field.rs:39:9 + --> $DIR/float-field.rs:60:9 | LL | { s.0x1.1e-1; } | ^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: suffixes on a tuple index are invalid - --> $DIR/float-field.rs:42:7 + --> $DIR/float-field.rs:64:9 | -LL | s.1e1f32; - | ^^^^^^ invalid suffix `f32` +LL | { s.1e1f32; } + | ^^^^^^ invalid suffix `f32` error: suffixes on a tuple index are invalid - --> $DIR/float-field.rs:45:7 + --> $DIR/float-field.rs:69:9 | -LL | s.1.1f32; - | ^^^^^^ invalid suffix `f32` +LL | { s.1.1f32; } + | ^^^^^^ invalid suffix `f32` error: suffixes on a tuple index are invalid - --> $DIR/float-field.rs:46:7 + --> $DIR/float-field.rs:71:9 | -LL | s.1.1e1f32; - | ^^^^^^^^ invalid suffix `f32` +LL | { s.1.1e1f32; } + | ^^^^^^^^ invalid suffix `f32` error: unexpected token: `1e+f32` - --> $DIR/float-field.rs:48:9 + --> $DIR/float-field.rs:74:9 | LL | { s.1e+f32; } | ^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+f32` - --> $DIR/float-field.rs:48:9 + --> $DIR/float-field.rs:74:9 | LL | { s.1e+f32; } | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e-f32` - --> $DIR/float-field.rs:51:9 + --> $DIR/float-field.rs:78:9 | LL | { s.1e-f32; } | ^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-f32` - --> $DIR/float-field.rs:51:9 + --> $DIR/float-field.rs:78:9 | LL | { s.1e-f32; } | ^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e+1f32` - --> $DIR/float-field.rs:54:9 + --> $DIR/float-field.rs:82:9 | LL | { s.1e+1f32; } | ^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e+1f32` - --> $DIR/float-field.rs:54:9 + --> $DIR/float-field.rs:82:9 | LL | { s.1e+1f32; } | ^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1e-1f32` - --> $DIR/float-field.rs:56:9 + --> $DIR/float-field.rs:85:9 | LL | { s.1e-1f32; } | ^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1e-1f32` - --> $DIR/float-field.rs:56:9 + --> $DIR/float-field.rs:85:9 | LL | { s.1e-1f32; } | ^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1.1e+1f32` - --> $DIR/float-field.rs:58:9 + --> $DIR/float-field.rs:88:9 | LL | { s.1.1e+1f32; } | ^^^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e+1f32` - --> $DIR/float-field.rs:58:9 + --> $DIR/float-field.rs:88:9 | LL | { s.1.1e+1f32; } | ^^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: unexpected token: `1.1e-1f32` - --> $DIR/float-field.rs:60:9 + --> $DIR/float-field.rs:91:9 | LL | { s.1.1e-1f32; } | ^^^^^^^^^ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `1.1e-1f32` - --> $DIR/float-field.rs:60:9 + --> $DIR/float-field.rs:91:9 | LL | { s.1.1e-1f32; } | ^^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error[E0609]: no field `1e1` on type `S` - --> $DIR/float-field.rs:6:7 + --> $DIR/float-field.rs:6:9 | -LL | s.1e1; - | ^^^ unknown field +LL | { s.1e1; } + | ^^^ unknown field | = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` - --> $DIR/float-field.rs:9:9 + --> $DIR/float-field.rs:12:11 | -LL | s.1.1e1; - | ^^^ unknown field +LL | { s.1.1e1; } + | ^^^ unknown field error[E0609]: no field `0x1e1` on type `S` - --> $DIR/float-field.rs:24:7 - | -LL | s.0x1e1; - | ^^^^^ unknown field - | - = note: available fields are: `0`, `1` - -error[E0609]: no field `0x1` on type `S` - --> $DIR/float-field.rs:25:7 - | -LL | s.0x1.; - | ^^^ unknown field - | - = note: available fields are: `0`, `1` - -error[E0609]: no field `0x1` on type `S` - --> $DIR/float-field.rs:28:7 - | -LL | s.0x1.1; - | ^^^ unknown field - | - = note: available fields are: `0`, `1` - -error[E0609]: no field `0x1` on type `S` - --> $DIR/float-field.rs:30:7 + --> $DIR/float-field.rs:34:9 | -LL | s.0x1.1e1; - | ^^^ unknown field +LL | { s.0x1e1; } + | ^^^^^ unknown field | = note: available fields are: `0`, `1` error[E0609]: no field `0x1e` on type `S` - --> $DIR/float-field.rs:34:7 + --> $DIR/float-field.rs:52:9 | -LL | s.0x1e+1; - | ^^^^ unknown field +LL | { s.0x1e+1; } + | ^^^^ unknown field | = note: available fields are: `0`, `1` error[E0609]: no field `0x1e` on type `S` - --> $DIR/float-field.rs:35:7 + --> $DIR/float-field.rs:54:9 | -LL | s.0x1e-1; - | ^^^^ unknown field +LL | { s.0x1e-1; } + | ^^^^ unknown field | = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `S` - --> $DIR/float-field.rs:42:7 + --> $DIR/float-field.rs:64:9 | -LL | s.1e1f32; - | ^^^^^^ unknown field +LL | { s.1e1f32; } + | ^^^^^^ unknown field | = note: available fields are: `0`, `1` error[E0609]: no field `f32` on type `(u8, u8)` - --> $DIR/float-field.rs:44:9 + --> $DIR/float-field.rs:67:11 | -LL | s.1.f32; - | ^^^ unknown field +LL | { s.1.f32; } + | ^^^ unknown field error[E0609]: no field `1e1` on type `(u8, u8)` - --> $DIR/float-field.rs:46:7 + --> $DIR/float-field.rs:71:9 | -LL | s.1.1e1f32; - | ^^^^^^^^ unknown field +LL | { s.1.1e1f32; } + | ^^^^^^^^ unknown field -error: aborting due to 55 previous errors +error: aborting due to 57 previous errors For more information about this error, try `rustc --explain E0609`. diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index a2b68fa966fcb..b27d9aef06614 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -7,9 +7,9 @@ LL | Vec::contains(&vec, &0); note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions: Vec::::new Vec::::with_capacity + Vec::::try_with_capacity Vec::::from_raw_parts - Vec::::new_in - and 2 others + and 4 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: the function `contains` is implemented on `[_]` | diff --git a/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs new file mode 100644 index 0000000000000..7a923179d3b73 --- /dev/null +++ b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.rs @@ -0,0 +1,11 @@ +struct What>(W, X); + +fn main() { + let mut b: What = What(5, vec![1, 2, 3]); + let c: What = What(1, String::from("meow")); + b = c; //~ ERROR mismatched types + + let mut f: What> = What(1, vec![String::from("meow")]); + let e: What = What(5, vec![1, 2, 3]); + f = e; //~ ERROR mismatched types +} diff --git a/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr new file mode 100644 index 0000000000000..d2b3397fbcb03 --- /dev/null +++ b/tests/ui/type/clarify-error-for-generics-with-default-issue-120785.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/clarify-error-for-generics-with-default-issue-120785.rs:6:9 + | +LL | let mut b: What = What(5, vec![1, 2, 3]); + | ----------- expected due to this type +LL | let c: What = What(1, String::from("meow")); +LL | b = c; + | ^ expected `What`, found `What` + | + = note: expected struct `What<_, Vec>` + found struct `What<_, String>` + +error[E0308]: mismatched types + --> $DIR/clarify-error-for-generics-with-default-issue-120785.rs:10:9 + | +LL | let mut f: What> = What(1, vec![String::from("meow")]); + | ------------------------ expected due to this type +LL | let e: What = What(5, vec![1, 2, 3]); +LL | f = e; + | ^ expected `What>`, found `What` + | + = note: expected struct `What<_, Vec>` + found struct `What<_, Vec>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index e1c5e45b3ebb7..9cfeb7a5d09d6 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -7,9 +7,9 @@ LL | Vec::::mew() note: if you're trying to build a new `Vec` consider using one of the following associated functions: Vec::::new Vec::::with_capacity + Vec::::try_with_capacity Vec::::from_raw_parts - Vec::::new_in - and 2 others + and 4 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: there is an associated function `new` with a similar name | diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed index b53d9d61d67f2..9b935b1667878 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.fixed @@ -8,6 +8,8 @@ trait Trait { type Assoc where u32: Copy; // Fine. type Assoc2 where u32: Copy, i32: Copy; + // + type Assoc3; } impl Trait for u32 { @@ -17,6 +19,8 @@ impl Trait for u32 { // Not fine, suggests moving `u32: Copy` type Assoc2 = () where i32: Copy, u32: Copy; //~^ WARNING where clause not allowed here + type Assoc3 = () where; + //~^ WARNING where clause not allowed here } impl Trait for i32 { @@ -25,6 +29,8 @@ impl Trait for i32 { // Not fine, suggests moving both. type Assoc2 = () where u32: Copy, i32: Copy; //~^ WARNING where clause not allowed here + type Assoc3 = () where; + //~^ WARNING where clause not allowed here } fn main() {} diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs index 18955dd8bcc39..b7a8ab3d4f782 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.rs @@ -8,6 +8,8 @@ trait Trait { type Assoc where u32: Copy; // Fine. type Assoc2 where u32: Copy, i32: Copy; + // + type Assoc3; } impl Trait for u32 { @@ -17,6 +19,8 @@ impl Trait for u32 { // Not fine, suggests moving `u32: Copy` type Assoc2 where u32: Copy = () where i32: Copy; //~^ WARNING where clause not allowed here + type Assoc3 where = (); + //~^ WARNING where clause not allowed here } impl Trait for i32 { @@ -25,6 +29,8 @@ impl Trait for i32 { // Not fine, suggests moving both. type Assoc2 where u32: Copy, i32: Copy = (); //~^ WARNING where clause not allowed here + type Assoc3 where = () where; + //~^ WARNING where clause not allowed here } fn main() {} diff --git a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr index 6ff9d2dd73b5b..5809ff8f80347 100644 --- a/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr +++ b/tests/ui/where-clauses/where-clause-placement-assoc-type-in-impl.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:15:16 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:17:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:18:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:20:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ @@ -26,7 +26,20 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here - --> $DIR/where-clause-placement-assoc-type-in-impl.rs:26:17 + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:22:17 + | +LL | type Assoc3 where = (); + | ^^^^^ + | + = note: see issue #89122 for more information +help: move it to the end of the type declaration + | +LL - type Assoc3 where = (); +LL + type Assoc3 = () where; + | + +warning: where clause not allowed here + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:30:17 | LL | type Assoc2 where u32: Copy, i32: Copy = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,5 +51,13 @@ LL - type Assoc2 where u32: Copy, i32: Copy = (); LL + type Assoc2 = () where u32: Copy, i32: Copy; | -warning: 3 warnings emitted +warning: where clause not allowed here + --> $DIR/where-clause-placement-assoc-type-in-impl.rs:32:17 + | +LL | type Assoc3 where = () where; + | ^^^^^ help: remove this `where` + | + = note: see issue #89122 for more information + +warning: 5 warnings emitted