diff --git a/Cargo.lock b/Cargo.lock index 9f6df6e14c6..7cde7989bc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -830,6 +830,41 @@ dependencies = [ "winapi", ] +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.27", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.27", +] + [[package]] name = "datafrog" version = "2.0.1" @@ -869,6 +904,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_setters" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.27", +] + [[package]] name = "diff" version = "0.1.13" @@ -1740,6 +1787,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -3416,7 +3469,7 @@ dependencies = [ "libc", "measureme", "memmap2", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3524,6 +3577,7 @@ name = "rustc_errors" version = "0.0.0" dependencies = [ "annotate-snippets", + "derive_setters", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -3566,6 +3620,7 @@ dependencies = [ "rustc_session", "rustc_span", "smallvec", + "termcolor", "thin-vec", "tracing", ] @@ -4135,7 +4190,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "parking_lot 0.11.2", + "parking_lot 0.12.1", "rustc-rayon-core", "rustc_ast", "rustc_data_structures", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 2a268c2da85..f2e90fd8eed 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1462,7 +1462,8 @@ pub enum ExprKind { /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct field. Field(P, Ident), /// An indexing operation (e.g., `foo[2]`). - Index(P, P), + /// The span represents the span of the `[2]`, including brackets. + Index(P, P, Span), /// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assignment). Range(Option>, Option>, RangeLimits), /// An underscore, used in destructuring assignment to ignore a value. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 84b56efd325..bae3979fbf9 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1400,7 +1400,7 @@ pub fn noop_visit_expr( fn_decl, body, fn_decl_span, - fn_arg_span: _, + fn_arg_span, }) => { vis.visit_closure_binder(binder); visit_constness(constness, vis); @@ -1408,6 +1408,7 @@ pub fn noop_visit_expr( vis.visit_fn_decl(fn_decl); vis.visit_expr(body); vis.visit_span(fn_decl_span); + vis.visit_span(fn_arg_span); } ExprKind::Block(blk, label) => { vis.visit_block(blk); @@ -1420,9 +1421,10 @@ pub fn noop_visit_expr( vis.visit_expr(expr); vis.visit_span(await_kw_span); } - ExprKind::Assign(el, er, _) => { + ExprKind::Assign(el, er, span) => { vis.visit_expr(el); vis.visit_expr(er); + vis.visit_span(span); } ExprKind::AssignOp(_op, el, er) => { vis.visit_expr(el); @@ -1432,9 +1434,10 @@ pub fn noop_visit_expr( vis.visit_expr(el); vis.visit_ident(ident); } - ExprKind::Index(el, er) => { + ExprKind::Index(el, er, brackets_span) => { vis.visit_expr(el); vis.visit_expr(er); + vis.visit_span(brackets_span); } ExprKind::Range(e1, e2, _lim) => { visit_opt(e1, |e1| vis.visit_expr(e1)); diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 096077e09bf..d3e43e20235 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -390,7 +390,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { | ast::ExprKind::Cast(x, _) | ast::ExprKind::Type(x, _) | ast::ExprKind::Field(x, _) - | ast::ExprKind::Index(x, _) => { + | ast::ExprKind::Index(x, _, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(x) } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index aed24e11c4e..6d474de2d15 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -885,7 +885,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_ident(*ident); } - ExprKind::Index(main_expression, index_expression) => { + ExprKind::Index(main_expression, index_expression, _) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0954cf03da9..42d0998d162 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -240,8 +240,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Field(el, ident) => { hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident)) } - ExprKind::Index(el, er) => { - hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er)) + ExprKind::Index(el, er, brackets_span) => { + hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span) } ExprKind::Range(Some(e1), Some(e2), RangeLimits::Closed) => { self.lower_expr_range_closed(e.span, e1, e2) @@ -657,14 +657,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Forwards a possible `#[track_caller]` annotation from `outer_hir_id` to - /// `inner_hir_id` in case the `closure_track_caller` feature is enabled. + /// `inner_hir_id` in case the `async_fn_track_caller` feature is enabled. pub(super) fn maybe_forward_track_caller( &mut self, span: Span, outer_hir_id: hir::HirId, inner_hir_id: hir::HirId, ) { - if self.tcx.features().closure_track_caller + if self.tcx.features().async_fn_track_caller && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5a0474dbc01..df73c721ade 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -56,6 +56,11 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { + let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller { + [sym::gen_future, sym::closure_track_caller][..].into() + } else { + [sym::gen_future][..].into() + }); let mut lctx = LoweringContext { // Pseudo-globals. tcx: self.tcx, @@ -83,7 +88,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), - allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()), + allow_gen_future, generics_def_id_map: Default::default(), }; lctx.with_hir_id_owner(owner, |lctx| f(lctx)); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 8767bbcb210..39741a03930 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -477,7 +477,7 @@ impl<'a> State<'a> { self.word("."); self.print_ident(*ident); } - ast::ExprKind::Index(expr, index) => { + ast::ExprKind::Index(expr, index, _) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.word("["); self.print_expr(index); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 28c0a444fc8..fe4a45b3898 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -751,9 +751,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) .must_apply_modulo_regions() { + let msg = if let ty::Adt(def, _) = ty.kind() + && [ + tcx.get_diagnostic_item(sym::Arc), + tcx.get_diagnostic_item(sym::Rc), + ].contains(&Some(def.did())) + { + "clone the value to increment its reference count" + } else { + "consider cloning the value if the performance cost is acceptable" + }; err.span_suggestion_verbose( span.shrink_to_hi(), - "consider cloning the value if the performance cost is acceptable", + msg, suggestion, Applicability::MachineApplicable, ); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index c92f32071f4..c66a2447356 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -79,7 +79,7 @@ impl<'tcx> BorrowExplanation<'tcx> { | hir::ExprKind::Unary(hir::UnOp::Deref, inner) | hir::ExprKind::Field(inner, _) | hir::ExprKind::MethodCall(_, inner, _, _) - | hir::ExprKind::Index(inner, _) = &expr.kind + | hir::ExprKind::Index(inner, _, _) = &expr.kind { expr = inner; } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 3c32121a51a..d62541daf07 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -567,7 +567,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; if let hir::ExprKind::Assign(place, rv, _sp) = expr.kind - && let hir::ExprKind::Index(val, index) = place.kind + && let hir::ExprKind::Index(val, index, _) = place.kind && (expr.span == self.assign_span || place.span == self.assign_span) { // val[index] = rv; @@ -620,7 +620,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ); self.suggested = true; } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind - && let hir::ExprKind::Index(val, index) = receiver.kind + && let hir::ExprKind::Index(val, index, _) = receiver.kind && expr.span == self.assign_span { // val[index].path(args..); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 30dfb2d919a..b8cd94e5422 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -784,13 +784,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// is considered a *lower bound*. If possible, we will modify /// the constraint to set it equal to one of the option regions. /// If we make any changes, returns true, else false. + /// + /// This function only adds the member constraints to the region graph, + /// it does not check them. They are later checked in + /// `check_member_constraints` after the region graph has been computed. #[instrument(skip(self, member_constraint_index), level = "debug")] fn apply_member_constraint( &mut self, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], - ) -> bool { + ) { + // Lazily compute the reverse graph, we'll need it later. + self.compute_reverse_scc_graph(); + // Create a mutable vector of the options. We'll try to winnow // them down. let mut choice_regions: Vec = choice_regions.to_vec(); @@ -805,10 +812,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { *c_r = self.scc_representatives[scc]; } - // The 'member region' in a member constraint is part of the - // hidden type, which must be in the root universe. Therefore, - // it cannot have any placeholders in its value. - assert!(self.scc_universes[scc] == ty::UniverseIndex::ROOT); + // If the member region lives in a higher universe, we currently choose + // the most conservative option by leaving it unchanged. + if self.scc_universes[scc] != ty::UniverseIndex::ROOT { + return; + } debug_assert!( self.scc_values.placeholders_contained_in(scc).next().is_none(), "scc {:?} in a member constraint has placeholder value: {:?}", @@ -832,7 +840,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { // free region that must outlive the member region `R0` (`UB: // R0`). Therefore, we need only keep an option `O` if `UB: O` // for all UB. - self.compute_reverse_scc_graph(); let universal_region_relations = &self.universal_region_relations; for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { debug!(?ub); @@ -867,7 +874,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } }) else { debug!("no unique minimum choice"); - return false; + return; }; let min_choice_scc = self.constraint_sccs.scc(min_choice); @@ -878,10 +885,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { min_choice, member_constraint_index, }); - - true - } else { - false } } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 90bde88f792..68dddd65acb 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -185,6 +185,21 @@ impl<'tcx> RegionInferenceContext<'tcx> { { tcx.fold_regions(ty, |region, _| match *region { ty::ReVar(vid) => { + let scc = self.constraint_sccs.scc(vid); + + // Special handling of higher-ranked regions. + if self.scc_universes[scc] != ty::UniverseIndex::ROOT { + match self.scc_values.placeholders_contained_in(scc).enumerate().last() { + // If the region contains a single placeholder then they're equal. + Some((0, placeholder)) => { + return ty::Region::new_placeholder(tcx, placeholder); + } + + // Fallback: this will produce a cryptic error message. + _ => return region, + } + } + // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); let upper_bound = &self.definitions[upper_bound]; diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index abb11ce7396..50d875dfae9 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -498,14 +498,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// Checks that the types internal to the `place` match up with /// what would be expected. + #[instrument(level = "debug", skip(self, location), ret)] fn sanitize_place( &mut self, place: &Place<'tcx>, location: Location, context: PlaceContext, ) -> PlaceTy<'tcx> { - debug!("sanitize_place: {:?}", place); - let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty); for elem in place.projection.iter() { @@ -608,7 +607,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self, location), ret, level = "debug")] fn sanitize_projection( &mut self, base: PlaceTy<'tcx>, @@ -617,7 +616,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { location: Location, context: PlaceContext, ) -> PlaceTy<'tcx> { - debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); let base_ty = base.ty; match pi { diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 79fae7f92f1..8d8db4c13fa 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -227,3 +227,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal .label = not a trait .str_lit = try using `#[derive({$sym})]` .other = for example, write `#[derive(Debug)]` for `Debug` + +builtin_macros_unnameable_test_items = cannot test inner items diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index cbf115127cf..bda473120ed 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -237,7 +237,7 @@ impl<'cx, 'a> Context<'cx, 'a> { ExprKind::If(local_expr, _, _) => { self.manage_cond_expr(local_expr); } - ExprKind::Index(prefix, suffix) => { + ExprKind::Index(prefix, suffix, _) => { self.manage_cond_expr(prefix); self.manage_cond_expr(suffix); } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 81b618548da..507b74c2437 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -4,10 +4,12 @@ use rustc_ast as ast; use rustc_ast::entry::EntryPointType; use rustc_ast::mut_visit::{ExpectOne, *}; use rustc_ast::ptr::P; +use rustc_ast::visit::{walk_item, Visitor}; use rustc_ast::{attr, ModKind}; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; +use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -137,11 +139,31 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { let prev_tests = mem::take(&mut self.tests); noop_visit_item_kind(&mut item.kind, self); self.add_test_cases(item.id, span, prev_tests); + } else { + // But in those cases, we emit a lint to warn the user of these missing tests. + walk_item(&mut InnerItemLinter { sess: self.cx.ext_cx.sess }, &item); } smallvec![P(item)] } } +struct InnerItemLinter<'a> { + sess: &'a Session, +} + +impl<'a> Visitor<'a> for InnerItemLinter<'_> { + fn visit_item(&mut self, i: &'a ast::Item) { + if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) { + self.sess.parse_sess.buffer_lint( + UNNAMEABLE_TEST_ITEMS, + attr.span, + i.id, + crate::fluent_generated::builtin_macros_unnameable_test_items, + ); + } + } +} + // Beware, this is duplicated in librustc_passes/entry.rs (with // `rustc_hir::Item`), so make sure to keep them in sync. fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 67ea20112fe..3081dcfa2b7 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -477,7 +477,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let layout::LayoutError::SizeOverflow(_) = err { + if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { self.0.sess.span_fatal(span, err.to_string()) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 08507e19652..88dcafa7370 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -476,7 +476,7 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) = err { + if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { self.sess().emit_fatal(respan(span, err.into_diagnostic())) } else { span_bug!(span, "failed to get layout for `{}`: {}", ty, err) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index cb093996d1d..3577fb2d951 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -985,7 +985,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> { #[inline] fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { - if let LayoutError::SizeOverflow(_) = err { + if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err { self.sess().emit_fatal(Spanned { span, node: err.into_diagnostic() }) } else { span_bug!(span, "failed to get layout for `{ty}`: {err:?}") diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 32e71c6a641..2be7bce115d 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -61,9 +61,6 @@ fn uncached_llvm_type<'a, 'tcx>( } Some(name) } - // Use identified structure types for ADT. Due to pointee types in LLVM IR their definition - // might be recursive. Other cases are non-recursive and we can use literal structure types. - ty::Adt(..) => Some(String::new()), _ => None, }; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 18268622341..ebf04e7a399 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -1,6 +1,7 @@ use pathdiff::diff_paths; use rustc_data_structures::fx::FxHashSet; use std::env; +use std::ffi::OsString; use std::fs; use std::path::{Path, PathBuf}; @@ -12,7 +13,7 @@ pub struct RPathConfig<'a> { pub linker_is_gnu: bool, } -pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { +pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { // No rpath on windows if !config.has_rpath { return Vec::new(); @@ -21,36 +22,38 @@ pub fn get_rpath_flags(config: &mut RPathConfig<'_>) -> Vec { debug!("preparing the RPATH!"); let rpaths = get_rpaths(config); - let mut flags = rpaths_to_flags(&rpaths); + let mut flags = rpaths_to_flags(rpaths); if config.linker_is_gnu { // Use DT_RUNPATH instead of DT_RPATH if available - flags.push("-Wl,--enable-new-dtags".to_owned()); + flags.push("-Wl,--enable-new-dtags".into()); // Set DF_ORIGIN for substitute $ORIGIN - flags.push("-Wl,-z,origin".to_owned()); + flags.push("-Wl,-z,origin".into()); } flags } -fn rpaths_to_flags(rpaths: &[String]) -> Vec { +fn rpaths_to_flags(rpaths: Vec) -> Vec { let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity for rpath in rpaths { - if rpath.contains(',') { + if rpath.to_string_lossy().contains(',') { ret.push("-Wl,-rpath".into()); ret.push("-Xlinker".into()); - ret.push(rpath.clone()); + ret.push(rpath); } else { - ret.push(format!("-Wl,-rpath,{}", &(*rpath))); + let mut single_arg = OsString::from("-Wl,-rpath,"); + single_arg.push(rpath); + ret.push(single_arg); } } ret } -fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec { +fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec { debug!("output: {:?}", config.out_filename.display()); debug!("libs:"); for libpath in config.libs { @@ -64,18 +67,18 @@ fn get_rpaths(config: &mut RPathConfig<'_>) -> Vec { debug!("rpaths:"); for rpath in &rpaths { - debug!(" {}", rpath); + debug!(" {:?}", rpath); } // Remove duplicates minimize_rpaths(&rpaths) } -fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec { +fn get_rpaths_relative_to_output(config: &mut RPathConfig<'_>) -> Vec { config.libs.iter().map(|a| get_rpath_relative_to_output(config, a)).collect() } -fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> String { +fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> OsString { // Mac doesn't appear to support $ORIGIN let prefix = if config.is_like_osx { "@loader_path" } else { "$ORIGIN" }; @@ -87,8 +90,11 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig<'_>, lib: &Path) -> Str let output = fs::canonicalize(&output).unwrap_or(output); let relative = path_relative_from(&lib, &output) .unwrap_or_else(|| panic!("couldn't create relative path from {output:?} to {lib:?}")); - // FIXME (#9639): This needs to handle non-utf8 paths - format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path")) + + let mut rpath = OsString::from(prefix); + rpath.push("/"); + rpath.push(relative); + rpath } // This routine is adapted from the *old* Path's `path_relative_from` @@ -99,7 +105,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option { diff_paths(path, base) } -fn minimize_rpaths(rpaths: &[String]) -> Vec { +fn minimize_rpaths(rpaths: &[OsString]) -> Vec { let mut set = FxHashSet::default(); let mut minimized = Vec::new(); for rpath in rpaths { diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 604f19144a6..ac2e54072c4 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -1,32 +1,33 @@ use super::RPathConfig; use super::{get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags}; +use std::ffi::OsString; use std::path::{Path, PathBuf}; #[test] fn test_rpaths_to_flags() { - let flags = rpaths_to_flags(&["path1".to_string(), "path2".to_string()]); + let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]); assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]); } #[test] fn test_minimize1() { - let res = minimize_rpaths(&["rpath1".to_string(), "rpath2".to_string(), "rpath1".to_string()]); + let res = minimize_rpaths(&["rpath1".into(), "rpath2".into(), "rpath1".into()]); assert!(res == ["rpath1", "rpath2",]); } #[test] fn test_minimize2() { let res = minimize_rpaths(&[ - "1a".to_string(), - "2".to_string(), - "2".to_string(), - "1a".to_string(), - "4a".to_string(), - "1a".to_string(), - "2".to_string(), - "3".to_string(), - "4a".to_string(), - "3".to_string(), + "1a".into(), + "2".into(), + "2".into(), + "1a".into(), + "4a".into(), + "1a".into(), + "2".into(), + "3".into(), + "4a".into(), + "3".into(), ]); assert!(res == ["1a", "2", "4a", "3",]); } @@ -58,15 +59,15 @@ fn test_rpath_relative() { #[test] fn test_xlinker() { - let args = rpaths_to_flags(&["a/normal/path".to_string(), "a,comma,path".to_string()]); + let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]); assert_eq!( args, vec![ - "-Wl,-rpath,a/normal/path".to_string(), - "-Wl,-rpath".to_string(), - "-Xlinker".to_string(), - "a,comma,path".to_string() + OsString::from("-Wl,-rpath,a/normal/path"), + OsString::from("-Wl,-rpath"), + OsString::from("-Xlinker"), + OsString::from("a,comma,path") ] ); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 92792ab6477..f6936c80b77 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -215,14 +215,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { - if !tcx.is_closure(did.to_def_id()) + let is_closure = tcx.is_closure(did.to_def_id()); + + if !is_closure && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); } - if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller { + if is_closure + && !tcx.features().closure_track_caller + && !attr.span.allows_unstable(sym::closure_track_caller) + { feature_err( &tcx.sess.parse_sess, sym::closure_track_caller, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 5f4f5434b18..2dc856528f5 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -157,7 +157,6 @@ impl MemPlace { } /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. - /// This is the inverse of `ref_to_mplace`. #[inline(always)] pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate { match self.meta { @@ -415,7 +414,7 @@ where } /// Take a value, which represents a (thin or wide) reference, and make it a place. - /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. + /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`. /// /// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not /// want to ever use the place for memory access! @@ -438,6 +437,18 @@ where Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.to_pointer(self)?, layout, meta)) } + /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. + /// `align` information is lost! + /// This is the inverse of `ref_to_mplace`. + pub fn mplace_to_ref( + &self, + mplace: &MPlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + let imm = mplace.to_ref(self); + let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; + Ok(ImmTy::from_immediate(imm, layout)) + } + /// Take an operand, representing a pointer, and dereference it to a place. /// Corresponds to the `*` operator in Rust. #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index bf33c5cca10..1bd21473182 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -852,10 +852,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; - let arg = ImmTy::from_immediate( - place.to_ref(self), - self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, place.layout.ty))?, - ); + let arg = self.mplace_to_ref(&place)?; let ret = MPlaceTy::fake_alloc_zst(self.layout_of(self.tcx.types.unit)?); self.eval_fn_call( diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index a5c3cb3f857..f77bd53e76c 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -35,7 +35,7 @@ elsa = "=1.7.1" itertools = "0.10.1" [dependencies.parking_lot] -version = "0.11" +version = "0.12" [target.'cfg(windows)'.dependencies.windows] version = "0.48.0" diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 8f8b9eaa274..d4532873854 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -27,9 +27,7 @@ use rustc_data_structures::profiling::{ use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; -use rustc_errors::{ - DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl, -}; +use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage}; use rustc_feature::find_gated_cfg; use rustc_fluent_macro::fluent_messages; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; @@ -1405,15 +1403,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( rustc_errors::ColorConfig::Auto, - None, - None, fallback_bundle, - false, - false, - None, - false, - false, - TerminalUrl::No, )); let handler = rustc_errors::Handler::with_emitter(emitter); diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index e8bcd7c1184..faab9f09da8 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -25,6 +25,7 @@ annotate-snippets = "0.9" termize = "0.1.1" serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" +derive_setters = "0.1.6" [target.'cfg(windows)'.dependencies.windows] version = "0.48.0" diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 44654571d43..0cae06881b1 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -7,8 +7,6 @@ //! //! The output types are defined in `rustc_session::config::ErrorOutputType`. -use Destination::*; - use rustc_span::source_map::SourceMap; use rustc_span::{FileLines, SourceFile, Span}; @@ -24,6 +22,7 @@ use crate::{ }; use rustc_lint_defs::pluralize; +use derive_setters::Setters; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_error_messages::{FluentArgs, SpanLabel}; @@ -35,8 +34,8 @@ use std::io::prelude::*; use std::io::{self, IsTerminal}; use std::iter; use std::path::Path; -use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; -use termcolor::{Buffer, Color, WriteColor}; +use termcolor::{Ansi, Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream}; +use termcolor::{Color, WriteColor}; /// Default column width, used in tests and when terminal dimensions cannot be determined. const DEFAULT_COLUMN_WIDTH: usize = 140; @@ -60,31 +59,15 @@ impl HumanReadableErrorType { } pub fn new_emitter( self, - dst: Box, - source_map: Option>, - bundle: Option>, + mut dst: Box, fallback_bundle: LazyFallbackBundle, - teach: bool, - diagnostic_width: Option, - macro_backtrace: bool, - track_diagnostics: bool, - terminal_url: TerminalUrl, ) -> EmitterWriter { let (short, color_config) = self.unzip(); let color = color_config.suggests_using_colors(); - EmitterWriter::new( - dst, - source_map, - bundle, - fallback_bundle, - short, - teach, - color, - diagnostic_width, - macro_backtrace, - track_diagnostics, - terminal_url, - ) + if !dst.supports_color() && color { + dst = Box::new(Ansi::new(dst)); + } + EmitterWriter::new(dst, fallback_bundle).short_message(short) } } @@ -639,10 +622,13 @@ impl ColorConfig { } /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short` +#[derive(Setters)] pub struct EmitterWriter { + #[setters(skip)] dst: Destination, sm: Option>, fluent_bundle: Option>, + #[setters(skip)] fallback_bundle: LazyFallbackBundle, short_message: bool, teach: bool, @@ -662,65 +648,32 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr( - color_config: ColorConfig, - source_map: Option>, - fluent_bundle: Option>, - fallback_bundle: LazyFallbackBundle, - short_message: bool, - teach: bool, - diagnostic_width: Option, - macro_backtrace: bool, - track_diagnostics: bool, - terminal_url: TerminalUrl, - ) -> EmitterWriter { - let dst = Destination::from_stderr(color_config); + pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { + let dst = from_stderr(color_config); + Self::create(dst, fallback_bundle) + } + + fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter { EmitterWriter { dst, - sm: source_map, - fluent_bundle, + sm: None, + fluent_bundle: None, fallback_bundle, - short_message, - teach, + short_message: false, + teach: false, ui_testing: false, - diagnostic_width, - macro_backtrace, - track_diagnostics, - terminal_url, + diagnostic_width: None, + macro_backtrace: false, + track_diagnostics: false, + terminal_url: TerminalUrl::No, } } pub fn new( - dst: Box, - source_map: Option>, - fluent_bundle: Option>, + dst: Box, fallback_bundle: LazyFallbackBundle, - short_message: bool, - teach: bool, - colored: bool, - diagnostic_width: Option, - macro_backtrace: bool, - track_diagnostics: bool, - terminal_url: TerminalUrl, ) -> EmitterWriter { - EmitterWriter { - dst: Raw(dst, colored), - sm: source_map, - fluent_bundle, - fallback_bundle, - short_message, - teach, - ui_testing: false, - diagnostic_width, - macro_backtrace, - track_diagnostics, - terminal_url, - } - } - - pub fn ui_testing(mut self, ui_testing: bool) -> Self { - self.ui_testing = ui_testing; - self + Self::create(dst, fallback_bundle) } fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> { @@ -2203,11 +2156,10 @@ impl EmitterWriter { Err(e) => panic!("failed to emit error: {e}"), } - let mut dst = self.dst.writable(); - match writeln!(dst) { + match writeln!(self.dst) { Err(e) => panic!("failed to emit error: {e}"), _ => { - if let Err(e) = dst.flush() { + if let Err(e) = self.dst.flush() { panic!("failed to emit error: {e}") } } @@ -2618,8 +2570,6 @@ fn emit_to_destination( ) -> io::Result<()> { use crate::lock; - let mut dst = dst.writable(); - // In order to prevent error message interleaving, where multiple error lines get intermixed // when multiple compiler processes error simultaneously, we emit errors with additional // steps. @@ -2635,7 +2585,8 @@ fn emit_to_destination( let _buffer_lock = lock::acquire_global_lock("rustc_errors"); for (pos, line) in rendered_buffer.iter().enumerate() { for part in line { - dst.apply_style(*lvl, part.style)?; + let style = part.style.color_spec(*lvl); + dst.set_color(&style)?; write!(dst, "{}", part.text)?; dst.reset()?; } @@ -2647,61 +2598,69 @@ fn emit_to_destination( Ok(()) } -pub enum Destination { - Terminal(StandardStream), - Buffered(BufferWriter), - // The bool denotes whether we should be emitting ansi color codes or not - Raw(Box<(dyn Write + Send)>, bool), +pub type Destination = Box<(dyn WriteColor + Send)>; + +struct Buffy { + buffer_writer: BufferWriter, + buffer: Buffer, } -pub enum WritableDst<'a> { - Terminal(&'a mut StandardStream), - Buffered(&'a mut BufferWriter, Buffer), - Raw(&'a mut (dyn Write + Send)), - ColoredRaw(Ansi<&'a mut (dyn Write + Send)>), +impl Write for Buffy { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buffer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer_writer.print(&self.buffer)?; + self.buffer.clear(); + Ok(()) + } } -impl Destination { - fn from_stderr(color: ColorConfig) -> Destination { - let choice = color.to_color_choice(); - // On Windows we'll be performing global synchronization on the entire - // system for emitting rustc errors, so there's no need to buffer - // anything. - // - // On non-Windows we rely on the atomicity of `write` to ensure errors - // don't get all jumbled up. - if cfg!(windows) { - Terminal(StandardStream::stderr(choice)) - } else { - Buffered(BufferWriter::stderr(choice)) - } - } - - fn writable(&mut self) -> WritableDst<'_> { - match *self { - Destination::Terminal(ref mut t) => WritableDst::Terminal(t), - Destination::Buffered(ref mut t) => { - let buf = t.buffer(); - WritableDst::Buffered(t, buf) - } - Destination::Raw(ref mut t, false) => WritableDst::Raw(t), - Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), +impl Drop for Buffy { + fn drop(&mut self) { + if !self.buffer.is_empty() { + self.flush().unwrap(); + panic!("buffers need to be flushed in order to print their contents"); } } +} +impl WriteColor for Buffy { fn supports_color(&self) -> bool { - match *self { - Self::Terminal(ref stream) => stream.supports_color(), - Self::Buffered(ref buffer) => buffer.buffer().supports_color(), - Self::Raw(_, supports_color) => supports_color, - } + self.buffer.supports_color() + } + + fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { + self.buffer.set_color(spec) + } + + fn reset(&mut self) -> io::Result<()> { + self.buffer.reset() } } -impl<'a> WritableDst<'a> { - fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> { +fn from_stderr(color: ColorConfig) -> Destination { + let choice = color.to_color_choice(); + // On Windows we'll be performing global synchronization on the entire + // system for emitting rustc errors, so there's no need to buffer + // anything. + // + // On non-Windows we rely on the atomicity of `write` to ensure errors + // don't get all jumbled up. + if cfg!(windows) { + Box::new(StandardStream::stderr(choice)) + } else { + let buffer_writer = BufferWriter::stderr(choice); + let buffer = buffer_writer.buffer(); + Box::new(Buffy { buffer_writer, buffer }) + } +} + +impl Style { + fn color_spec(&self, lvl: Level) -> ColorSpec { let mut spec = ColorSpec::new(); - match style { + match self { Style::Addition => { spec.set_fg(Some(Color::Green)).set_intense(true); } @@ -2746,53 +2705,7 @@ impl<'a> WritableDst<'a> { spec.set_bold(true); } } - self.set_color(&spec) - } - - fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> { - match *self { - WritableDst::Terminal(ref mut t) => t.set_color(color), - WritableDst::Buffered(_, ref mut t) => t.set_color(color), - WritableDst::ColoredRaw(ref mut t) => t.set_color(color), - WritableDst::Raw(_) => Ok(()), - } - } - - fn reset(&mut self) -> io::Result<()> { - match *self { - WritableDst::Terminal(ref mut t) => t.reset(), - WritableDst::Buffered(_, ref mut t) => t.reset(), - WritableDst::ColoredRaw(ref mut t) => t.reset(), - WritableDst::Raw(_) => Ok(()), - } - } -} - -impl<'a> Write for WritableDst<'a> { - fn write(&mut self, bytes: &[u8]) -> io::Result { - match *self { - WritableDst::Terminal(ref mut t) => t.write(bytes), - WritableDst::Buffered(_, ref mut buf) => buf.write(bytes), - WritableDst::Raw(ref mut w) => w.write(bytes), - WritableDst::ColoredRaw(ref mut t) => t.write(bytes), - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - WritableDst::Terminal(ref mut t) => t.flush(), - WritableDst::Buffered(_, ref mut buf) => buf.flush(), - WritableDst::Raw(ref mut w) => w.flush(), - WritableDst::ColoredRaw(ref mut w) => w.flush(), - } - } -} - -impl<'a> Drop for WritableDst<'a> { - fn drop(&mut self) { - if let WritableDst::Buffered(ref mut dst, ref mut buf) = self { - drop(dst.print(buf)); - } + spec } } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 55f7c485024..b8f58e3057c 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -10,6 +10,7 @@ // FIXME: spec the JSON output properly. use rustc_span::source_map::{FilePathMapping, SourceMap}; +use termcolor::{ColorSpec, WriteColor}; use crate::emitter::{Emitter, HumanReadableErrorType}; use crate::registry::Registry; @@ -356,20 +357,29 @@ impl Diagnostic { self.0.lock().unwrap().flush() } } + impl WriteColor for BufWriter { + fn supports_color(&self) -> bool { + false + } + + fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> { + Ok(()) + } + + fn reset(&mut self) -> io::Result<()> { + Ok(()) + } + } let buf = BufWriter::default(); let output = buf.clone(); je.json_rendered - .new_emitter( - Box::new(buf), - Some(je.sm.clone()), - je.fluent_bundle.clone(), - je.fallback_bundle.clone(), - false, - je.diagnostic_width, - je.macro_backtrace, - je.track_diagnostics, - je.terminal_url, - ) + .new_emitter(Box::new(buf), je.fallback_bundle.clone()) + .sm(Some(je.sm.clone())) + .fluent_bundle(je.fluent_bundle.clone()) + .diagnostic_width(je.diagnostic_width) + .macro_backtrace(je.macro_backtrace) + .track_diagnostics(je.track_diagnostics) + .terminal_url(je.terminal_url) .ui_testing(je.ui_testing) .emit_diagnostic(diag); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 3b753629128..7d660d2dbaa 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -557,18 +557,7 @@ impl Handler { sm: Option>, fallback_bundle: LazyFallbackBundle, ) -> Self { - let emitter = Box::new(EmitterWriter::stderr( - ColorConfig::Auto, - sm, - None, - fallback_bundle, - false, - false, - None, - false, - false, - TerminalUrl::No, - )); + let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm)); Self::with_emitter(emitter) } pub fn disable_warnings(mut self) -> Self { diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 2dae0e3f53c..02da5b5dc53 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -27,3 +27,4 @@ rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.12" tracing = "0.1" +termcolor = "1.2" diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 30fa5fea407..8e3219c138c 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -8,7 +8,8 @@ use rustc_span::{BytePos, Span}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl}; +use rustc_errors::{Handler, MultiSpan, PResult}; +use termcolor::WriteColor; use std::io; use std::io::prelude::*; @@ -29,19 +30,9 @@ fn create_test_handler() -> (Handler, Lrc, Arc>>) { vec![crate::DEFAULT_LOCALE_RESOURCE, rustc_parse::DEFAULT_LOCALE_RESOURCE], false, ); - let emitter = EmitterWriter::new( - Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - None, - fallback_bundle, - false, - false, - false, - Some(140), - false, - false, - TerminalUrl::No, - ); + let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + .sm(Some(source_map.clone())) + .diagnostic_width(Some(140)); let handler = Handler::with_emitter(Box::new(emitter)); (handler, source_map, output) } @@ -165,6 +156,20 @@ pub(crate) struct Shared { pub data: Arc>, } +impl WriteColor for Shared { + fn supports_color(&self) -> bool { + false + } + + fn set_color(&mut self, _spec: &termcolor::ColorSpec) -> io::Result<()> { + Ok(()) + } + + fn reset(&mut self) -> io::Result<()> { + Ok(()) + } +} + impl Write for Shared { fn write(&mut self, buf: &[u8]) -> io::Result { self.data.lock().unwrap().write(buf) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index ff25f744ded..2a0dab64af5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -339,6 +339,8 @@ declare_features! ( (active, async_closure, "1.37.0", Some(62290), None), /// Allows async functions to be declared, implemented, and used in traits. (active, async_fn_in_trait, "1.66.0", Some(91611), None), + /// Allows `#[track_caller]` on async functions. + (active, async_fn_track_caller, "CURRENT_RUSTC_VERSION", Some(110011), None), /// Allows builtin # foo() syntax (active, builtin_syntax, "1.71.0", Some(110680), None), /// Allows `c"foo"` literals. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6b76e16825f..bc05565fed4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1754,7 +1754,7 @@ impl Expr<'_> { ExprKind::Unary(UnOp::Deref, _) => true, - ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _) => { + ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _, _) => { allow_projections_from(base) || base.is_place_expr(allow_projections_from) } @@ -1831,7 +1831,7 @@ impl Expr<'_> { ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) - | ExprKind::Index(base, _) + | ExprKind::Index(base, _, _) | ExprKind::AddrOf(.., base) | ExprKind::Cast(base, _) => { // This isn't exactly true for `Index` and all `Unary`, but we are using this @@ -2015,7 +2015,9 @@ pub enum ExprKind<'hir> { /// Access of a named (e.g., `obj.foo`) or unnamed (e.g., `obj.0`) struct or tuple field. Field(&'hir Expr<'hir>, Ident), /// An indexing operation (`foo[2]`). - Index(&'hir Expr<'hir>, &'hir Expr<'hir>), + /// Similar to [`ExprKind::MethodCall`], the final `Span` represents the span of the brackets + /// and index. + Index(&'hir Expr<'hir>, &'hir Expr<'hir>, Span), /// Path to a definition, possibly containing lifetime or type parameters. Path(QPath<'hir>), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a8a94e6a476..9d1d899eef0 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -780,7 +780,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(subexpression); visitor.visit_ident(ident); } - ExprKind::Index(ref main_expression, ref index_expression) => { + ExprKind::Index(ref main_expression, ref index_expression, _) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e64848da86b..16d4d099c7e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -245,13 +245,14 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { } // `ForeignItem`s are handled separately. hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::TyAlias(hir_ty, ..) => { + hir::ItemKind::TyAlias(hir_ty, ast_generics) => { if tcx.features().lazy_type_alias || tcx.type_of(item.owner_id).skip_binder().has_opaque_types() { // Bounds of lazy type aliases and of eager ones that contain opaque types are respected. // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`. check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); + check_variances_for_type_defn(tcx, item, ast_generics); } } _ => {} @@ -1700,10 +1701,27 @@ fn check_variances_for_type_defn<'tcx>( hir_generics: &hir::Generics<'_>, ) { let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id); - for field in tcx.adt_def(item.owner_id).all_fields() { - if field.ty(tcx, identity_args).references_error() { - return; + + match item.kind { + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { + for field in tcx.adt_def(item.owner_id).all_fields() { + if field.ty(tcx, identity_args).references_error() { + return; + } + } } + ItemKind::TyAlias(..) => { + let ty = tcx.type_of(item.owner_id).instantiate_identity(); + + if tcx.features().lazy_type_alias || ty.has_opaque_types() { + if ty.references_error() { + return; + } + } else { + bug!(); + } + } + _ => bug!(), } let ty_predicates = tcx.predicates_of(item.owner_id); diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index ec8889781f4..4a3d522e488 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -6,7 +6,7 @@ use hir::def_id::{DefId, LocalDefId}; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use super::terms::VarianceTerm::*; @@ -78,6 +78,12 @@ pub fn add_constraints_from_crate<'a, 'tcx>( } } DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id), + DefKind::TyAlias + if tcx.features().lazy_type_alias + || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => + { + constraint_cx.build_constraints_for_item(def_id) + } _ => {} } } @@ -101,7 +107,18 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let inferred_start = self.terms_cx.inferred_starts[&def_id]; let current_item = &CurrentItem { inferred_start }; - match tcx.type_of(def_id).instantiate_identity().kind() { + let ty = tcx.type_of(def_id).instantiate_identity(); + + // The type as returned by `type_of` is the underlying type and generally not a weak projection. + // Therefore we need to check the `DefKind` first. + if let DefKind::TyAlias = tcx.def_kind(def_id) + && (tcx.features().lazy_type_alias || ty.has_opaque_types()) + { + self.add_constraints_from_ty(current_item, ty, self.covariant); + return; + } + + match ty.kind() { ty::Adt(def, _) => { // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -127,6 +144,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Error(_) => {} + _ => { span_bug!( tcx.def_span(def_id), @@ -252,10 +270,14 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_args(current, def.did(), args, variance); } - ty::Alias(_, ref data) => { + ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, ref data) => { self.add_constraints_from_invariant_args(current, data.args, variance); } + ty::Alias(ty::Weak, ref data) => { + self.add_constraints_from_args(current, data.def_id, data.args, variance); + } + ty::Dynamic(data, r, _) => { // The type `dyn Trait +'a` is covariant w/r/t `'a`: self.add_constraints_from_region(current, r, variance); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 6952a3fa66f..2ef294c6793 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -8,7 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt}; -use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; use std::ops::ControlFlow; /// Defines the `TermsContext` basically houses an arena where we can @@ -56,6 +56,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } + DefKind::TyAlias + if tcx.features().lazy_type_alias + || tcx.type_of(item_def_id).instantiate_identity().has_opaque_types() => + { + // These are inferred. + let crate_map = tcx.crate_variances(()); + return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); + } DefKind::OpaqueTy => { return variance_of_opaque(tcx, item_def_id); } diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs index ed03c5da26f..1ef3d383bd8 100644 --- a/compiler/rustc_hir_analysis/src/variance/terms.rs +++ b/compiler/rustc_hir_analysis/src/variance/terms.rs @@ -12,7 +12,7 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use std::fmt; use self::VarianceTerm::*; @@ -97,6 +97,12 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( } } DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id), + DefKind::TyAlias + if tcx.features().lazy_type_alias + || tcx.type_of(def_id).instantiate_identity().has_opaque_types() => + { + terms_cx.add_inferreds_for_item(def_id) + } _ => {} } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2d8b956771b..fda46798708 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1526,7 +1526,7 @@ impl<'a> State<'a> { self.word("."); self.print_ident(ident); } - hir::ExprKind::Index(expr, index) => { + hir::ExprKind::Index(expr, index, _) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); self.word("["); self.print_expr(index); @@ -2419,7 +2419,7 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool { | hir::ExprKind::Cast(x, _) | hir::ExprKind::Type(x, _) | hir::ExprKind::Field(x, _) - | hir::ExprKind::Index(x, _) => { + | hir::ExprKind::Index(x, _, _) => { // `&X { y: 1 }, X { y: 1 }.y` contains_exterior_struct_lit(x) } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 80d7cc57edb..2af8648455b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -345,7 +345,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_struct(expr, expected, qpath, fields, base_expr) } ExprKind::Field(base, field) => self.check_field(expr, &base, field, expected), - ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr), + ExprKind::Index(base, idx, brackets_span) => { + self.check_expr_index(base, idx, expr, brackets_span) + } ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src), hir::ExprKind::Err(guar) => Ty::new_error(tcx, guar), } @@ -2840,6 +2842,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, idx: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, + brackets_span: Span, ) -> Ty<'tcx> { let base_t = self.check_expr(&base); let idx_t = self.check_expr(&idx); @@ -2873,7 +2876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = type_error_struct!( self.tcx.sess, - expr.span, + brackets_span, base_t, E0608, "cannot index into a value of type `{base_t}`", @@ -2887,16 +2890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node && i < types.len().try_into().expect("expected tuple index to be < usize length") { - let snip = self.tcx.sess.source_map().span_to_snippet(base.span); - if let Ok(snip) = snip { - err.span_suggestion( - expr.span, - "to access tuple elements, use", - format!("{snip}.{i}"), - Applicability::MachineApplicable, - ); - needs_note = false; - } + + err.span_suggestion( + brackets_span, + "to access tuple elements, use", + format!(".{i}"), + Applicability::MachineApplicable, + ); + needs_note = false; } else if let ExprKind::Path(..) = idx.peel_borrows().kind { err.span_label(idx.span, "cannot access tuple elements at a variable index"); } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index a59061cbf67..840910732d8 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -211,7 +211,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.select_from_expr(base); } - hir::ExprKind::Index(lhs, rhs) => { + hir::ExprKind::Index(lhs, rhs, _) => { // lhs[rhs] self.select_from_expr(lhs); self.consume_expr(rhs); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d4edd08d302..89bbb4c2203 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1620,8 +1620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .enumerate() .filter(|x| x.1.hir_id == *hir_id) - .map(|(i, _)| init_tup.get(i).unwrap()) - .next() + .find_map(|(i, _)| init_tup.get(i)) { self.note_type_is_not_clone_inner_expr(init) } else { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 0700e2e0554..4ea53c7eaae 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -198,13 +198,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } /// Like `pat_ty`, but ignores implicit `&` patterns. + #[instrument(level = "debug", skip(self), ret)] fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult> { let base_ty = self.node_ty(pat.hir_id)?; - debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty); + trace!(?base_ty); // This code detects whether we are looking at a `ref x`, // and if so, figures out what the type *being borrowed* is. - let ret_ty = match pat.kind { + match pat.kind { PatKind::Binding(..) => { let bm = *self .typeck_results @@ -217,21 +218,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. match base_ty.builtin_deref(false) { - Some(t) => t.ty, + Some(t) => Ok(t.ty), None => { - debug!("By-ref binding of non-derefable type {:?}", base_ty); - return Err(()); + debug!("By-ref binding of non-derefable type"); + Err(()) } } } else { - base_ty + Ok(base_ty) } } - _ => base_ty, - }; - debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty); - - Ok(ret_ty) + _ => Ok(base_ty), + } } pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult> { @@ -299,13 +297,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(crate) fn cat_expr_unadjusted( &self, expr: &hir::Expr<'_>, ) -> McResult> { - debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr); - let expr_ty = self.expr_ty(expr)?; match expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => { @@ -319,7 +315,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { hir::ExprKind::Field(ref base, _) => { let base = self.cat_expr(base)?; - debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); + debug!(?base); let field_idx = self .typeck_results @@ -336,7 +332,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { )) } - hir::ExprKind::Index(ref base, _) => { + hir::ExprKind::Index(ref base, _, _) => { if self.typeck_results.is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. @@ -389,7 +385,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span), ret)] pub(crate) fn cat_res( &self, hir_id: hir::HirId, @@ -430,6 +426,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. + #[instrument(level = "debug", skip(self), ret)] fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult> { let closure_expr_def_id = self.body_owner; @@ -439,24 +436,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; let var_ty = self.node_ty(var_id)?; - let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()); - - debug!("cat_upvar ret={:?}", ret); - Ok(ret) + Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new())) } + #[instrument(level = "debug", skip(self), ret)] pub(crate) fn cat_rvalue( &self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>, ) -> PlaceWithHirId<'tcx> { - debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span); - let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()); - debug!("cat_rvalue ret={:?}", ret); - ret + PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) } + #[instrument(level = "debug", skip(self, node), ret)] pub(crate) fn cat_projection( &self, node: &N, @@ -464,16 +457,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ty: Ty<'tcx>, kind: ProjectionKind, ) -> PlaceWithHirId<'tcx> { + let place_ty = base_place.place.ty(); let mut projections = base_place.place.projections; + + let node_ty = self.typeck_results.node_type(node.hir_id()); + // Opaque types can't have field projections, but we can instead convert + // the current place in-place (heh) to the hidden type, and then apply all + // follow up projections on that. + if node_ty != place_ty && place_ty.has_opaque_types() { + projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); + } projections.push(Projection { kind, ty }); - let ret = PlaceWithHirId::new( + PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, base_place.place.base, projections, - ); - debug!("cat_field ret {:?}", ret); - ret + ) } #[instrument(level = "debug", skip(self))] @@ -497,7 +497,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_deref(expr, base) } - #[instrument(level = "debug", skip(self, node))] + #[instrument(level = "debug", skip(self, node), ret)] fn cat_deref( &self, node: &impl HirNode, @@ -514,14 +514,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let mut projections = base_place.place.projections; projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); - let ret = PlaceWithHirId::new( + Ok(PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, base_place.place.base, projections, - ); - debug!("cat_deref ret {:?}", ret); - Ok(ret) + )) } pub(crate) fn cat_pattern( @@ -603,6 +601,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } + /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it + /// is being matched against. + /// + /// In general, the way that this works is that we walk down the pattern, + /// constructing a `PlaceWithHirId` that represents the path that will be taken + /// to reach the value being matched. + #[instrument(skip(self, op), ret, level = "debug")] fn cat_pattern_( &self, mut place_with_id: PlaceWithHirId<'tcx>, @@ -612,15 +617,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { where F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { - // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it - // is being matched against. - // - // In general, the way that this works is that we walk down the pattern, - // constructing a `PlaceWithHirId` that represents the path that will be taken - // to reach the value being matched. - - debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id); - // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. // `PlaceWithHirId`s are constructed differently from patterns. For example, in // @@ -654,11 +650,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { - debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); + debug!("applying adjustment to place_with_id={:?}", place_with_id); place_with_id = self.cat_deref(pat, place_with_id)?; } let place_with_id = place_with_id; // lose mutability - debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id); + debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id); // Invoke the callback, but only now, after the `place_with_id` has adjusted. // diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 1eb84eb1637..406434e09e6 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut exprs = vec![expr]; while let hir::ExprKind::Field(ref expr, _) - | hir::ExprKind::Index(ref expr, _) + | hir::ExprKind::Index(ref expr, _, _) | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind { exprs.push(expr); diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs index 091e88abe97..04d84102336 100644 --- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs +++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs @@ -40,7 +40,7 @@ fn record_rvalue_scope_rec( hir::ExprKind::AddrOf(_, _, subexpr) | hir::ExprKind::Unary(hir::UnOp::Deref, subexpr) | hir::ExprKind::Field(subexpr, _) - | hir::ExprKind::Index(subexpr, _) => { + | hir::ExprKind::Index(subexpr, _, _) => { expr = subexpr; } _ => { diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index be939560c45..1a41786d251 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -264,12 +264,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty); // If we have an origin, store it. - if let Some(origin) = origin { - let origin = if enable_precise_capture(span) { - (origin.0, origin.1) - } else { - (origin.0, Place { projections: vec![], ..origin.1 }) - }; + if let Some(mut origin) = origin { + if !enable_precise_capture(span) { + // Without precise captures, we just capture the base and ignore + // the projections. + origin.1.projections.clear() + } self.typeck_results .borrow_mut() @@ -294,10 +294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Equate the type variables for the upvars with the actual types. let final_upvar_tys = self.final_upvar_tys(closure_def_id); - debug!( - "analyze_closure: id={:?} args={:?} final_upvar_tys={:?}", - closure_hir_id, args, final_upvar_tys - ); + debug!(?closure_hir_id, ?args, ?final_upvar_tys); // Build a tuple (U0..Un) of the final upvar types U0..Un // and unify the upvar tuple type in the closure with it: @@ -338,10 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let upvar_ty = captured_place.place.ty(); let capture = captured_place.info.capture_kind; - debug!( - "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}", - captured_place.place, upvar_ty, capture, captured_place.mutability, - ); + debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability); apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region) }) @@ -679,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match (p1.kind, p2.kind) { // Paths are the same, continue to next loop. (ProjectionKind::Deref, ProjectionKind::Deref) => {} + (ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {} (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) if i1 == i2 => {} @@ -701,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { l @ (ProjectionKind::Index | ProjectionKind::Subslice | ProjectionKind::Deref + | ProjectionKind::OpaqueCast | ProjectionKind::Field(..)), r @ (ProjectionKind::Index | ProjectionKind::Subslice | ProjectionKind::Deref + | ProjectionKind::OpaqueCast | ProjectionKind::Field(..)), ) => bug!( "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", @@ -1890,6 +1887,7 @@ fn restrict_capture_precision( return (place, curr_mode); } ProjectionKind::Deref => {} + ProjectionKind::OpaqueCast => {} ProjectionKind::Field(..) => {} // ignore } } @@ -1946,6 +1944,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String ProjectionKind::Deref => String::from("Deref"), ProjectionKind::Index => String::from("Index"), ProjectionKind::Subslice => String::from("Subslice"), + ProjectionKind::OpaqueCast => String::from("OpaqueCast"), }; if i != 0 { projections_str.push(','); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 6f47623ec43..603681bbc99 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -210,7 +210,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // to use builtin indexing because the index type is known to be // usize-ish fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) { - if let hir::ExprKind::Index(ref base, ref index) = e.kind { + if let hir::ExprKind::Index(ref base, ref index, _) = e.kind { // All valid indexing looks like this; might encounter non-valid indexes at this point. let base_ty = self.typeck_results.expr_ty_adjusted_opt(base); if base_ty.is_none() { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 433735e827b..6d5db3336cf 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -481,3 +481,31 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) } } } + +impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { + fn to_trace( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + } + } +} + +impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { + fn to_trace( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + } + } +} diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 54d901f20da..9d7a9fefd08 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -562,15 +562,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { V: TypeFoldable>, { let needs_canonical_flags = if canonicalize_region_mode.any() { - TypeFlags::HAS_INFER | - TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` - TypeFlags::HAS_TY_PLACEHOLDER | - TypeFlags::HAS_CT_PLACEHOLDER + TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS } else { - TypeFlags::HAS_INFER - | TypeFlags::HAS_RE_PLACEHOLDER - | TypeFlags::HAS_TY_PLACEHOLDER - | TypeFlags::HAS_CT_PLACEHOLDER + TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER }; // Fast path: nothing that needs to be canonicalized. diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 7739cf1ee05..75cca973306 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -351,6 +351,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( ) } } + ty::RePlaceholder(_) => { + explain_free_region( + tcx, + &mut err, + &format!("hidden type `{}` captures ", hidden_ty), + hidden_region, + "", + ); + } ty::ReError(_) => { err.delay_as_bug(); } @@ -1635,6 +1644,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), + ValuePairs::ExistentialTraitRef(_) => { + (false, Mismatch::Fixed("existential trait ref")) + } + ValuePairs::ExistentialProjection(_) => { + (false, Mismatch::Fixed("existential projection")) + } }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2139,6 +2154,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Regions(exp_found) => self.expected_found_str(exp_found), infer::Terms(exp_found) => self.expected_found_str_term(exp_found), infer::Aliases(exp_found) => self.expected_found_str(exp_found), + infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), + infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a73e84f94c4..aaabf1482e2 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -374,6 +374,8 @@ pub enum ValuePairs<'tcx> { TraitRefs(ExpectedFound>), PolyTraitRefs(ExpectedFound>), Sigs(ExpectedFound>), + ExistentialTraitRef(ExpectedFound>), + ExistentialProjection(ExpectedFound>), } impl<'tcx> ValuePairs<'tcx> { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 1b4c8ce120a..c4a7f717840 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -130,8 +130,6 @@ lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}` .help = was set with `--cfg` but isn't in the `--check-cfg` expected values -lint_builtin_unnameable_test_items = cannot test inner items - lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done @@ -169,8 +167,9 @@ lint_check_name_warning = {$msg} lint_command_line_source = `forbid` lint level was set on command line -lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` - .label = this is where the previous identifier occurred +lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as identifiers, which look alike + .current_use = this identifier can be confused with `{$existing_sym}` + .other_use = other identifier used here lint_cstring_ptr = getting the inner pointer of a temporary `CString` .as_ptr_label = this pointer will be invalid diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index cc6d5330c33..5e61073694f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -35,7 +35,7 @@ use crate::{ BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue, - BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit, BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, SuggestChangingAssocTypes, @@ -1259,8 +1259,8 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { declare_lint! { /// The `ungated_async_fn_track_caller` lint warns when the - /// `#[track_caller]` attribute is used on an async function, method, or - /// closure, without enabling the corresponding unstable feature flag. + /// `#[track_caller]` attribute is used on an async function + /// without enabling the corresponding unstable feature flag. /// /// ### Example /// @@ -1274,13 +1274,13 @@ declare_lint! { /// ### Explanation /// /// The attribute must be used in conjunction with the - /// [`closure_track_caller` feature flag]. Otherwise, the `#[track_caller]` + /// [`async_fn_track_caller` feature flag]. Otherwise, the `#[track_caller]` /// annotation will function as a no-op. /// - /// [`closure_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/closure-track-caller.html + /// [`async_fn_track_caller` feature flag]: https://doc.rust-lang.org/beta/unstable-book/language-features/async-fn-track-caller.html UNGATED_ASYNC_FN_TRACK_CALLER, Warn, - "enabling track_caller on an async fn is a no-op unless the closure_track_caller feature is enabled" + "enabling track_caller on an async fn is a no-op unless the async_fn_track_caller feature is enabled" } declare_lint_pass!( @@ -1300,7 +1300,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { def_id: LocalDefId, ) { if fn_kind.asyncness() == IsAsync::Async - && !cx.tcx.features().closure_track_caller + && !cx.tcx.features().async_fn_track_caller // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { @@ -1770,82 +1770,6 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } } -declare_lint! { - /// The `unnameable_test_items` lint detects [`#[test]`][test] functions - /// that are not able to be run by the test harness because they are in a - /// position where they are not nameable. - /// - /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute - /// - /// ### Example - /// - /// ```rust,test - /// fn main() { - /// #[test] - /// fn foo() { - /// // This test will not fail because it does not run. - /// assert_eq!(1, 2); - /// } - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In order for the test harness to run a test, the test function must be - /// located in a position where it can be accessed from the crate root. - /// This generally means it must be defined in a module, and not anywhere - /// else such as inside another function. The compiler previously allowed - /// this without an error, so a lint was added as an alert that a test is - /// not being used. Whether or not this should be allowed has not yet been - /// decided, see [RFC 2471] and [issue #36629]. - /// - /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443 - /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629 - UNNAMEABLE_TEST_ITEMS, - Warn, - "detects an item that cannot be named being marked as `#[test_case]`", - report_in_external_macro -} - -pub struct UnnameableTestItems { - boundary: Option, // Id of the item under which things are not nameable - items_nameable: bool, -} - -impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]); - -impl UnnameableTestItems { - pub fn new() -> Self { - Self { boundary: None, items_nameable: true } - } -} - -impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { - fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - if self.items_nameable { - if let hir::ItemKind::Mod(..) = it.kind { - } else { - self.items_nameable = false; - self.boundary = Some(it.owner_id); - } - return; - } - - let attrs = cx.tcx.hir().attrs(it.hir_id()); - if let Some(attr) = attr::find_by_name(attrs, sym::rustc_test_marker) { - cx.emit_spanned_lint(UNNAMEABLE_TEST_ITEMS, attr.span, BuiltinUnnameableTestItems); - } - } - - fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) { - if !self.items_nameable && self.boundary == Some(it.owner_id) { - self.items_nameable = true; - } - } -} - declare_lint! { /// The `keyword_idents` lint detects edition keywords being used as an /// identifier. diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9bd442e64e3..80bf53ea866 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -189,8 +189,6 @@ late_lint_methods!( [ pub BuiltinCombinedLateLintPass, [ - // Tracks state across modules - UnnameableTestItems: UnnameableTestItems::new(), // Tracks attributes of parents MissingDoc: MissingDoc::new(), // Builds a global list of all impls of `Debug`. diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 604daf2e90a..70311a5c576 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -250,7 +250,7 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { rustc_session::parse::add_feature_diagnostics( diag, &self.parse_sess, - sym::closure_track_caller, + sym::async_fn_track_caller, ); diag } @@ -370,10 +370,6 @@ pub enum BuiltinEllipsisInclusiveRangePatternsLint { }, } -#[derive(LintDiagnostic)] -#[diag(lint_builtin_unnameable_test_items)] -pub struct BuiltinUnnameableTestItems; - #[derive(LintDiagnostic)] #[diag(lint_builtin_keyword_idents)] pub struct BuiltinKeywordIdents { @@ -1087,8 +1083,10 @@ pub struct IdentifierUncommonCodepoints; pub struct ConfusableIdentifierPair { pub existing_sym: Symbol, pub sym: Symbol, - #[label] + #[label(lint_other_use)] pub label: Span, + #[label(lint_current_use)] + pub main_label: Span, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 4af879b4e91..62bb8c2c67d 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -222,6 +222,7 @@ impl EarlyLintPass for NonAsciiIdents { existing_sym: *existing_symbol, sym: symbol, label: *existing_span, + main_label: sp, }, ); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index a3c5ca4cda1..3db6b302790 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -653,7 +653,7 @@ trait UnusedDelimLint { ExprKind::Call(fn_, _params) => fn_, ExprKind::Cast(expr, _ty) => expr, ExprKind::Type(expr, _ty) => expr, - ExprKind::Index(base, _subscript) => base, + ExprKind::Index(base, _subscript, _) => base, _ => break, }; if !classify::expr_requires_semi_to_be_stmt(innermost) { @@ -830,7 +830,7 @@ trait UnusedDelimLint { (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None, true) } - Index(_, ref value) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false), + Index(_, ref value, _) => (value, UnusedDelimsCtx::IndexExpr, false, None, None, false), Assign(_, ref value, _) | AssignOp(.., ref value) => { (value, UnusedDelimsCtx::AssignedValue, false, None, None, false) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1a612731808..3747e562cec 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2846,6 +2846,45 @@ declare_lint! { }; } +declare_lint! { + /// The `unnameable_test_items` lint detects [`#[test]`][test] functions + /// that are not able to be run by the test harness because they are in a + /// position where they are not nameable. + /// + /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute + /// + /// ### Example + /// + /// ```rust,test + /// fn main() { + /// #[test] + /// fn foo() { + /// // This test will not fail because it does not run. + /// assert_eq!(1, 2); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order for the test harness to run a test, the test function must be + /// located in a position where it can be accessed from the crate root. + /// This generally means it must be defined in a module, and not anywhere + /// else such as inside another function. The compiler previously allowed + /// this without an error, so a lint was added as an alert that a test is + /// not being used. Whether or not this should be allowed has not yet been + /// decided, see [RFC 2471] and [issue #36629]. + /// + /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443 + /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629 + pub UNNAMEABLE_TEST_ITEMS, + Warn, + "detects an item that cannot be named being marked as `#[test_case]`", + report_in_external_macro +} + declare_lint! { /// The `useless_deprecated` lint detects deprecation attributes with no effect. /// @@ -3403,6 +3442,7 @@ declare_lint_pass! { UNKNOWN_CRATE_TYPES, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNKNOWN_LINTS, + UNNAMEABLE_TEST_ITEMS, UNNAMEABLE_TYPES, UNREACHABLE_CODE, UNREACHABLE_PATTERNS, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d72053ca985..f12094a271f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -30,6 +30,7 @@ use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, AssocItemContainer, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; @@ -1034,7 +1035,7 @@ fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) { } } -fn should_encode_variances(def_kind: DefKind) -> bool { +fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: DefKind) -> bool { match def_kind { DefKind::Struct | DefKind::Union @@ -1053,7 +1054,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Static(..) | DefKind::Const | DefKind::ForeignMod - | DefKind::TyAlias | DefKind::Impl { .. } | DefKind::Trait | DefKind::TraitAlias @@ -1067,6 +1067,10 @@ fn should_encode_variances(def_kind: DefKind) -> bool { | DefKind::Closure | DefKind::Generator | DefKind::ExternCrate => false, + DefKind::TyAlias => { + tcx.features().lazy_type_alias + || tcx.type_of(def_id).instantiate_identity().has_opaque_types() + } } } @@ -1349,7 +1353,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_default_body_stability(def_id); self.encode_deprecation(def_id); } - if should_encode_variances(def_kind) { + if should_encode_variances(tcx, def_id, def_kind) { let v = self.tcx.variances_of(def_id); record_array!(self.tables.variances_of[def_id] <- v); } diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 8a22de931c3..32f3a177508 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -36,6 +36,10 @@ pub enum ProjectionKind { /// A subslice covering a range of values like `B[x..y]`. Subslice, + + /// A conversion from an opaque type to its hidden type so we can + /// do further projections on it. + OpaqueCast, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1189dcdfcbb..a02f9a9f796 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -749,7 +749,7 @@ rustc_queries! { separate_provide_extern } - /// Gets a map with the variance of every item; use `item_variance` instead. + /// Gets a map with the variance of every item; use `variances_of` instead. query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> { arena_cache desc { "computing the variances for items in this crate" } diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index b21a00e4122..9d63d291854 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,7 +1,6 @@ use std::ops::ControlFlow; use rustc_data_structures::intern::Interned; -use rustc_query_system::cache::Cache; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; @@ -11,9 +10,10 @@ use crate::ty::{ TypeVisitor, }; +mod cache; pub mod inspect; -pub type EvaluationCache<'tcx> = Cache, QueryResult<'tcx>>; +pub use cache::{CacheData, EvaluationCache}; /// A goal is a statement, i.e. `predicate`, we want to prove /// given some assumptions, i.e. `param_env`. @@ -147,7 +147,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs new file mode 100644 index 00000000000..9898b0019bb --- /dev/null +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -0,0 +1,100 @@ +use super::{CanonicalInput, QueryResult}; +use crate::ty::TyCtxt; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::Lock; +use rustc_query_system::cache::WithDepNode; +use rustc_query_system::dep_graph::DepNodeIndex; +use rustc_session::Limit; +/// The trait solver cache used by `-Ztrait-solver=next`. +/// +/// FIXME(@lcnr): link to some official documentation of how +/// this works. +#[derive(Default)] +pub struct EvaluationCache<'tcx> { + map: Lock, CacheEntry<'tcx>>>, +} + +pub struct CacheData<'tcx> { + pub result: QueryResult<'tcx>, + pub reached_depth: usize, + pub encountered_overflow: bool, +} + +impl<'tcx> EvaluationCache<'tcx> { + /// Insert a final result into the global cache. + pub fn insert( + &self, + key: CanonicalInput<'tcx>, + reached_depth: usize, + did_overflow: bool, + cycle_participants: FxHashSet>, + dep_node: DepNodeIndex, + result: QueryResult<'tcx>, + ) { + let mut map = self.map.borrow_mut(); + let entry = map.entry(key).or_default(); + let data = WithDepNode::new(dep_node, result); + entry.cycle_participants.extend(cycle_participants); + if did_overflow { + entry.with_overflow.insert(reached_depth, data); + } else { + entry.success = Some(Success { data, reached_depth }); + } + } + + /// Try to fetch a cached result, checking the recursion limit + /// and handling root goals of coinductive cycles. + /// + /// If this returns `Some` the cache result can be used. + pub fn get( + &self, + tcx: TyCtxt<'tcx>, + key: CanonicalInput<'tcx>, + cycle_participant_in_stack: impl FnOnce(&FxHashSet>) -> bool, + available_depth: Limit, + ) -> Option> { + let map = self.map.borrow(); + let entry = map.get(&key)?; + + if cycle_participant_in_stack(&entry.cycle_participants) { + return None; + } + + if let Some(ref success) = entry.success { + if available_depth.value_within_limit(success.reached_depth) { + return Some(CacheData { + result: success.data.get(tcx), + reached_depth: success.reached_depth, + encountered_overflow: false, + }); + } + } + + entry.with_overflow.get(&available_depth.0).map(|e| CacheData { + result: e.get(tcx), + reached_depth: available_depth.0, + encountered_overflow: true, + }) + } +} + +struct Success<'tcx> { + data: WithDepNode>, + reached_depth: usize, +} + +/// The cache entry for a goal `CanonicalInput`. +/// +/// This contains results whose computation never hit the +/// recursion limit in `success`, and all results which hit +/// the recursion limit in `with_overflow`. +#[derive(Default)] +struct CacheEntry<'tcx> { + success: Option>, + /// We have to be careful when caching roots of cycles. + /// + /// See the doc comment of `StackEntry::cycle_participants` for more + /// details. + cycle_participants: FxHashSet>, + with_overflow: FxHashMap>>, +} diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index e793f481995..4e2af3816ac 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -73,12 +73,15 @@ pub struct GoalCandidate<'tcx> { pub enum CandidateKind<'tcx> { /// Probe entered when normalizing the self ty during candidate assembly NormalizedSelfTyAssembly, - DynUpcastingAssembly, /// A normal candidate for proving a goal - Candidate { - name: String, - result: QueryResult<'tcx>, - }, + Candidate { name: String, result: QueryResult<'tcx> }, + /// Used in the probe that wraps normalizing the non-self type for the unsize + /// trait, which is also structurally matched on. + UnsizeAssembly, + /// During upcasting from some source object to target object type, used to + /// do a probe to find out what projection type(s) may be used to prove that + /// the source type upholds all of the target type's object bounds. + UpcastProbe, } impl Debug for GoalCandidate<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index f1e567e9bf8..8759fecb05a 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -100,8 +100,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { CandidateKind::NormalizedSelfTyAssembly => { writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:") } - CandidateKind::DynUpcastingAssembly => { - writeln!(self.f, "ASSEMBLING CANDIDATES FOR DYN UPCASTING:") + CandidateKind::UnsizeAssembly => { + writeln!(self.f, "ASSEMBLING CANDIDATES FOR UNSIZING:") + } + CandidateKind::UpcastProbe => { + writeln!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:") } CandidateKind::Candidate { name, result } => { writeln!(self.f, "CANDIDATE {name}: {result:?}") diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 42f22604975..2e5c6a44579 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -174,6 +174,8 @@ impl<'tcx> CapturedPlace<'tcx> { // Ignore derefs for now, as they are likely caused by // autoderefs that don't appear in the original code. HirProjectionKind::Deref => {} + // Just change the type to the hidden type, so we can actually project. + HirProjectionKind::OpaqueCast => {} proj => bug!("Unexpected projection {:?} in captured place", proj), } ty = proj.ty; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6b0f0132062..48aa25dba6d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1338,12 +1338,25 @@ impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { } } +impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx) + } +} + impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx) } } +impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { + let p: Predicate<'tcx> = self.to_predicate(tcx); + p.expect_clause() + } +} + impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> { let p: Predicate<'tcx> = self.to_predicate(tcx); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6e68022031a..d3fd49150ba 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2734,8 +2734,9 @@ forward_display_to_print! { // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. ty::PolyExistentialPredicate<'tcx>, + ty::PolyExistentialProjection<'tcx>, + ty::PolyExistentialTraitRef<'tcx>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, - ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 520bb55e031..156eda477ad 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -88,14 +88,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { self.has_type_flags(TypeFlags::HAS_INFER) } fn has_placeholders(&self) -> bool { - self.has_type_flags( - TypeFlags::HAS_RE_PLACEHOLDER - | TypeFlags::HAS_TY_PLACEHOLDER - | TypeFlags::HAS_CT_PLACEHOLDER, - ) + self.has_type_flags(TypeFlags::HAS_PLACEHOLDER) } fn has_non_region_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER) + self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER) } fn has_param(&self) -> bool { self.has_type_flags(TypeFlags::HAS_PARAM) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 7756d5d4879..2e7ef265a93 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -236,6 +236,9 @@ fn strip_prefix<'a, 'tcx>( } assert_matches!(iter.next(), Some(ProjectionElem::Field(..))); } + HirProjectionKind::OpaqueCast => { + assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..))); + } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index ff4620948fa..994ac8a3286 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -469,11 +469,17 @@ impl<'tcx> Cx<'tcx> { } } - hir::ExprKind::Index(ref lhs, ref index) => { + hir::ExprKind::Index(ref lhs, ref index, brackets_span) => { if self.typeck_results().is_method_call(expr) { let lhs = self.mirror_expr(lhs); let index = self.mirror_expr(index); - self.overloaded_place(expr, expr_ty, None, Box::new([lhs, index]), expr.span) + self.overloaded_place( + expr, + expr_ty, + None, + Box::new([lhs, index]), + brackets_span, + ) } else { ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) } } @@ -1072,6 +1078,9 @@ impl<'tcx> Cx<'tcx> { variant_index, name: field, }, + HirProjectionKind::OpaqueCast => { + ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) } + } HirProjectionKind::Index | HirProjectionKind::Subslice => { // We don't capture these projections, so we can ignore them here continue; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c0459789805..e409c7c6781 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -857,7 +857,7 @@ impl<'a> Parser<'a> { let msg = format!( "cast cannot be followed by {}", match with_postfix.kind { - ExprKind::Index(_, _) => "indexing", + ExprKind::Index(..) => "indexing", ExprKind::Try(_) => "`?`", ExprKind::Field(_, _) => "a field access", ExprKind::MethodCall(_) => "a method call", @@ -1304,7 +1304,10 @@ impl<'a> Parser<'a> { let index = self.parse_expr()?; self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?; self.expect(&token::CloseDelim(Delimiter::Bracket))?; - Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index))) + Ok(self.mk_expr( + lo.to(self.prev_token.span), + self.mk_index(base, index, open_delim_span.to(self.prev_token.span)), + )) } /// Assuming we have just parsed `.`, continue parsing into an expression. @@ -3366,8 +3369,8 @@ impl<'a> Parser<'a> { ExprKind::Binary(binop, lhs, rhs) } - fn mk_index(&self, expr: P, idx: P) -> ExprKind { - ExprKind::Index(expr, idx) + fn mk_index(&self, expr: P, idx: P, brackets_span: Span) -> ExprKind { + ExprKind::Index(expr, idx, brackets_span) } fn mk_call(&self, f: P, args: ThinVec>) -> ExprKind { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 15757a0f1ad..0c0b8b6d094 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1061,7 +1061,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&l, ln) } - hir::ExprKind::Index(ref l, ref r) | hir::ExprKind::Binary(_, ref l, ref r) => { + hir::ExprKind::Index(ref l, ref r, _) | hir::ExprKind::Binary(_, ref l, ref r) => { let r_succ = self.propagate_through_expr(&r, succ); self.propagate_through_expr(&l, r_succ) } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index e02cf38b671..584355df802 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [lib] [dependencies] -parking_lot = "0.11" +parking_lot = "0.12" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index b87757a3e1a..3803f7eca0a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,4 +1,3 @@ -use parking_lot::Mutex; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef}; @@ -88,7 +87,7 @@ pub struct DepGraphData { colors: DepNodeColorMap, - processed_side_effects: Mutex>, + processed_side_effects: Lock>, /// When we load, there may be `.o` files, cached MIR, or other such /// things available to us. If we find that they are not dirty, we diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index d2140161f1d..bfc51da170d 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -21,12 +21,11 @@ use { parking_lot::{Condvar, Mutex}, rayon_core, rustc_data_structures::fx::FxHashSet, - rustc_data_structures::sync::Lock, - rustc_data_structures::sync::Lrc, rustc_data_structures::{defer, jobserver}, rustc_span::DUMMY_SP, std::iter, std::process, + std::sync::Arc, }; /// Represents a span and a query key. @@ -191,7 +190,7 @@ struct QueryWaiter { query: Option, condvar: Condvar, span: Span, - cycle: Lock>>, + cycle: Mutex>>, } #[cfg(parallel_compiler)] @@ -205,20 +204,20 @@ impl QueryWaiter { #[cfg(parallel_compiler)] struct QueryLatchInfo { complete: bool, - waiters: Vec>>, + waiters: Vec>>, } #[cfg(parallel_compiler)] #[derive(Clone)] pub(super) struct QueryLatch { - info: Lrc>>, + info: Arc>>, } #[cfg(parallel_compiler)] impl QueryLatch { fn new() -> Self { QueryLatch { - info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), + info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })), } } @@ -229,11 +228,11 @@ impl QueryLatch { span: Span, ) -> Result<(), CycleError> { let waiter = - Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() }); + Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); self.wait_on_inner(&waiter); // FIXME: Get rid of this lock. We have ownership of the QueryWaiter - // although another thread may still have a Lrc reference so we cannot - // use Lrc::get_mut + // although another thread may still have a Arc reference so we cannot + // use Arc::get_mut let mut cycle = waiter.cycle.lock(); match cycle.take() { None => Ok(()), @@ -242,7 +241,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Lrc>) { + fn wait_on_inner(&self, waiter: &Arc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -276,7 +275,7 @@ impl QueryLatch { /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. - fn extract_waiter(&self, waiter: usize) -> Lrc> { + fn extract_waiter(&self, waiter: usize) -> Arc> { let mut info = self.info.lock(); debug_assert!(!info.complete); // Remove the waiter from the list of waiters @@ -428,7 +427,7 @@ where fn remove_cycle( query_map: &QueryMap, jobs: &mut Vec, - wakelist: &mut Vec>>, + wakelist: &mut Vec>>, ) -> bool { let mut visited = FxHashSet::default(); let mut stack = Vec::new(); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0e9d74480a9..7b590d16d8c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4269,7 +4269,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ExprKind::ConstBlock(ref ct) => { self.resolve_anon_const(ct, AnonConstKind::InlineConst); } - ExprKind::Index(ref elem, ref idx) => { + ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); self.visit_expr(idx); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ad22e7c703d..ac745d16161 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1350,18 +1350,15 @@ fn default_emitter( ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { - let emitter = EmitterWriter::stderr( - color_config, - Some(source_map), - bundle, - fallback_bundle, - short, - sopts.unstable_opts.teach, - sopts.diagnostic_width, - macro_backtrace, - track_diagnostics, - terminal_url, - ); + let emitter = EmitterWriter::stderr(color_config, fallback_bundle) + .fluent_bundle(bundle) + .sm(Some(source_map)) + .short_message(short) + .teach(sopts.unstable_opts.teach) + .diagnostic_width(sopts.diagnostic_width) + .macro_backtrace(macro_backtrace) + .track_diagnostics(track_diagnostics) + .terminal_url(terminal_url); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } } @@ -1794,18 +1791,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr( - color_config, - None, - None, - fallback_bundle, - short, - false, - None, - false, - false, - TerminalUrl::No, - )) + Box::new(EmitterWriter::stderr(color_config, fallback_bundle).short_message(short)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic( pretty, diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 4811bb2c354..96a118e590f 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -248,9 +248,9 @@ fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option String { +fn sort_by_words(name: &str) -> Vec<&str> { let mut split_words: Vec<&str> = name.split('_').collect(); // We are sorting primitive &strs and can use unstable sort here. split_words.sort_unstable(); - split_words.join("_") + split_words } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9cff8a688ff..44820ae6f72 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -400,6 +400,7 @@ symbols! { async_await, async_closure, async_fn_in_trait, + async_fn_track_caller, atomic, atomic_mod, atomics, diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs index 75a65a26849..6389d68641a 100644 --- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs index f2242bbe087..a177a73483f 100644 --- a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, features: "+m".into(), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs index 01e773fae97..fd620696cb2 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, features: "+m,+c".into(), panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 1b4af95cb8a..6b839d64b87 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -162,7 +162,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.add_goal(Goal::new( self.tcx(), param_env, - ty::Binder::dummy(ty::ProjectionPredicate { projection_ty: alias, term: other }), + ty::ProjectionPredicate { projection_ty: alias, term: other }, )); Ok(()) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 8bf003f863e..267f345c062 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -1,6 +1,5 @@ //! Code shared by trait and projection goals for candidate assembly. -use super::search_graph::OverflowHandler; use super::{EvalCtxt, SolverMode}; use crate::traits::coherence; use rustc_hir::def_id::DefId; @@ -315,7 +314,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return ambig; } - let mut candidates = self.assemble_candidates_via_self_ty(goal); + let mut candidates = self.assemble_candidates_via_self_ty(goal, 0); self.assemble_blanket_impl_candidates(goal, &mut candidates); @@ -351,6 +350,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { fn assemble_candidates_via_self_ty>( &mut self, goal: Goal<'tcx, G>, + num_steps: usize, ) -> Vec> { debug_assert_eq!(goal, self.resolve_vars_if_possible(goal)); if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) { @@ -369,7 +369,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.assemble_coherence_unknowable_candidates(goal, &mut candidates); - self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates); + self.assemble_candidates_after_normalizing_self_ty(goal, &mut candidates, num_steps); candidates } @@ -393,49 +393,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut self, goal: Goal<'tcx, G>, candidates: &mut Vec>, + num_steps: usize, ) { let tcx = self.tcx(); let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else { return }; - let normalized_self_candidates: Result<_, NoSolution> = - self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| { - ecx.with_incremented_depth( - |ecx| { - let result = ecx.evaluate_added_goals_and_make_canonical_response( - Certainty::OVERFLOW, - )?; - Ok(vec![Candidate { - source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), - result, - }]) - }, - |ecx| { - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = goal.with( - tcx, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: normalized_ty.into(), - }), - ); - ecx.add_goal(normalizes_to_goal); - let _ = ecx.try_evaluate_added_goals().inspect_err(|_| { - debug!("self type normalization failed"); - })?; - let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); - debug!(?normalized_ty, "self type normalized"); - // NOTE: Alternatively we could call `evaluate_goal` here and only - // have a `Normalized` candidate. This doesn't work as long as we - // use `CandidateSource` in winnowing. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); - Ok(ecx.assemble_candidates_via_self_ty(goal)) - }, - ) - }); - - if let Ok(normalized_self_candidates) = normalized_self_candidates { - candidates.extend(normalized_self_candidates); - } + candidates.extend(self.probe(|_| CandidateKind::NormalizedSelfTyAssembly).enter(|ecx| { + if num_steps < ecx.local_overflow_limit() { + let normalized_ty = ecx.next_ty_infer(); + let normalizes_to_goal = goal.with( + tcx, + ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() }, + ); + ecx.add_goal(normalizes_to_goal); + if let Err(NoSolution) = ecx.try_evaluate_added_goals() { + debug!("self type normalization failed"); + return vec![]; + } + let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty); + debug!(?normalized_ty, "self type normalized"); + // NOTE: Alternatively we could call `evaluate_goal` here and only + // have a `Normalized` candidate. This doesn't work as long as we + // use `CandidateSource` in winnowing. + let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + ecx.assemble_candidates_via_self_ty(goal, num_steps + 1) + } else { + match ecx.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW) { + Ok(result) => vec![Candidate { + source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + result, + }], + Err(NoSolution) => vec![], + } + } + })); } #[instrument(level = "debug", skip_all)] @@ -533,7 +524,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (), // FIXME: These should ideally not exist as a self type. It would be nice for - // the builtin auto trait impls of generators should instead directly recurse + // the builtin auto trait impls of generators to instead directly recurse // into the witness. ty::GeneratorWitness(_) | ty::GeneratorWitnessMIR(_, _) => (), diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 88771f90756..a9d182abfb7 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -207,23 +207,18 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { t } - fn fold_region(&mut self, mut r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match self.canonicalize_mode { - CanonicalizeMode::Input => { - // Don't resolve infer vars in input, since it affects - // caching and may cause trait selection bugs which rely - // on regions to be equal. - } - CanonicalizeMode::Response { .. } => { - if let ty::ReVar(vid) = *r { - r = self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid); - } - } + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReVar(vid) = *r { + let resolved_region = self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.infcx.tcx, vid); + assert_eq!( + r, resolved_region, + "region var should have been resolved, {r} -> {resolved_region}" + ); } let kind = match *r { @@ -278,38 +273,22 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { ty::Region::new_late_bound(self.interner(), self.binder_index, br) } - fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { let kind = match *t.kind() { - ty::Infer(ty::TyVar(mut vid)) => { - // We need to canonicalize the *root* of our ty var. - // This is so that our canonical response correctly reflects - // any equated inference vars correctly! - let root_vid = self.infcx.root_var(vid); - if root_vid != vid { - t = Ty::new_var(self.infcx.tcx, root_vid); - vid = root_vid; - } - - match self.infcx.probe_ty_var(vid) { - Ok(t) => return self.fold_ty(t), - Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), - } + ty::Infer(ty::TyVar(vid)) => { + assert_eq!(self.infcx.root_var(vid), vid, "ty vid should have been resolved"); + let Err(ui) = self.infcx.probe_ty_var(vid) else { + bug!("ty var should have been resolved: {t}"); + }; + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) } ty::Infer(ty::IntVar(vid)) => { - let nt = self.infcx.opportunistic_resolve_int_var(vid); - if nt != t { - return self.fold_ty(nt); - } else { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int) - } + assert_eq!(self.infcx.opportunistic_resolve_int_var(vid), t); + CanonicalVarKind::Ty(CanonicalTyVarKind::Int) } ty::Infer(ty::FloatVar(vid)) => { - let nt = self.infcx.opportunistic_resolve_float_var(vid); - if nt != t { - return self.fold_ty(nt); - } else { - CanonicalVarKind::Ty(CanonicalTyVarKind::Float) - } + assert_eq!(self.infcx.opportunistic_resolve_float_var(vid), t); + CanonicalVarKind::Ty(CanonicalTyVarKind::Float) } ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("fresh var during canonicalization: {t:?}") @@ -372,22 +351,19 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { Ty::new_bound(self.infcx.tcx, self.binder_index, bt) } - fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { let kind = match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => { - // We need to canonicalize the *root* of our const var. - // This is so that our canonical response correctly reflects - // any equated inference vars correctly! - let root_vid = self.infcx.root_const_var(vid); - if root_vid != vid { - c = ty::Const::new_var(self.infcx.tcx, root_vid, c.ty()); - vid = root_vid; - } - - match self.infcx.probe_const_var(vid) { - Ok(c) => return self.fold_const(c), - Err(universe) => CanonicalVarKind::Const(universe, c.ty()), - } + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + assert_eq!( + self.infcx.root_const_var(vid), + vid, + "const var should have been resolved" + ); + let Err(ui) = self.infcx.probe_const_var(vid) else { + bug!("const var should have been resolved"); + }; + // FIXME: we should fold this ty eventually + CanonicalVarKind::Const(ui, c.ty()) } ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => { bug!("fresh var during canonicalization: {c:?}") diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 485bc912c44..5ec9ddfe64a 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -1,20 +1,21 @@ +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ - DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin, - TyCtxtInferExt, + DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt, }; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; +use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::solve::inspect; use rustc_middle::traits::solve::{ CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, PredefinedOpaques, PredefinedOpaquesData, QueryResult, }; -use rustc_middle::traits::DefiningAnchor; +use rustc_middle::traits::{specialization_graph, DefiningAnchor}; use rustc_middle::ty::{ self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -24,11 +25,10 @@ use rustc_span::DUMMY_SP; use std::io::Write; use std::ops::ControlFlow; -use crate::traits::specialization_graph; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; -use super::search_graph::{self, OverflowHandler}; +use super::search_graph; use super::SolverMode; use super::{search_graph::SearchGraph, Goal}; pub use select::InferCtxtSelectExt; @@ -55,6 +55,9 @@ pub struct EvalCtxt<'a, 'tcx> { /// the job already. infcx: &'a InferCtxt<'tcx>, + /// The variable info for the `var_values`, only used to make an ambiguous response + /// with no constraints. + variables: CanonicalVarInfos<'tcx>, pub(super) var_values: CanonicalVarValues<'tcx>, predefined_opaques_in_body: PredefinedOpaques<'tcx>, @@ -171,6 +174,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.search_graph.solver_mode() } + pub(super) fn local_overflow_limit(&self) -> usize { + self.search_graph.local_overflow_limit() + } + /// Creates a root evaluation context and search graph. This should only be /// used from outside of any evaluation, and other methods should be preferred /// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]). @@ -184,18 +191,19 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut ecx = EvalCtxt { search_graph: &mut search_graph, - infcx: infcx, + infcx, + nested_goals: NestedGoals::new(), + inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree), + // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. predefined_opaques_in_body: infcx .tcx .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), - // Only relevant when canonicalizing the response. max_input_universe: ty::UniverseIndex::ROOT, + variables: ty::List::empty(), var_values: CanonicalVarValues::dummy(), - nested_goals: NestedGoals::new(), tainted: Ok(()), - inspect: ProofTreeBuilder::new_maybe_root(infcx.tcx, generate_proof_tree), }; let result = f(&mut ecx); @@ -245,6 +253,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let mut ecx = EvalCtxt { infcx, + variables: canonical_input.variables, var_values, predefined_opaques_in_body: input.predefined_opaques_in_body, max_input_universe: canonical_input.max_universe, @@ -300,24 +309,26 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Deal with overflow, caching, and coinduction. // // The actual solver logic happens in `ecx.compute_goal`. - search_graph.with_new_goal( - tcx, - canonical_input, - goal_evaluation, - |search_graph, goal_evaluation| { - EvalCtxt::enter_canonical( - tcx, - search_graph, - canonical_input, - goal_evaluation, - |ecx, goal| { - let result = ecx.compute_goal(goal); - ecx.inspect.query_result(result); - result - }, - ) - }, - ) + ensure_sufficient_stack(|| { + search_graph.with_new_goal( + tcx, + canonical_input, + goal_evaluation, + |search_graph, goal_evaluation| { + EvalCtxt::enter_canonical( + tcx, + search_graph, + canonical_input, + goal_evaluation, + |ecx, goal| { + let result = ecx.compute_goal(goal); + ecx.inspect.query_result(result); + result + }, + ) + }, + ) + }) } /// Recursively evaluates `goal`, returning whether any inference vars have @@ -329,6 +340,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { ) -> Result<(bool, Certainty, Vec>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack); + let encountered_overflow = self.search_graph.encountered_overflow(); let canonical_response = EvalCtxt::evaluate_canonical_goal( self.tcx(), self.search_graph, @@ -377,6 +389,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { && !self.search_graph.in_cycle() { debug!("rerunning goal to check result is stable"); + self.search_graph.reset_encountered_overflow(encountered_overflow); let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); let new_canonical_response = EvalCtxt::evaluate_canonical_goal( self.tcx(), @@ -471,101 +484,22 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let inspect = self.inspect.new_evaluate_added_goals(); let inspect = core::mem::replace(&mut self.inspect, inspect); - let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); - let mut new_goals = NestedGoals::new(); - - let response = self.repeat_while_none( - |_| Ok(Certainty::OVERFLOW), - |this| { - this.inspect.evaluate_added_goals_loop_start(); - - let mut has_changed = Err(Certainty::Yes); - - if let Some(goal) = goals.normalizes_to_hack_goal.take() { - // Replace the goal with an unconstrained infer var, so the - // RHS does not affect projection candidate assembly. - let unconstrained_rhs = this.next_term_infer_of_kind(goal.predicate.term); - let unconstrained_goal = goal.with( - this.tcx(), - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: goal.predicate.projection_ty, - term: unconstrained_rhs, - }), - ); - - let (_, certainty, instantiate_goals) = - match this.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal) { - Ok(r) => r, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - new_goals.goals.extend(instantiate_goals); - - // Finally, equate the goal's RHS with the unconstrained var. - // We put the nested goals from this into goals instead of - // next_goals to avoid needing to process the loop one extra - // time if this goal returns something -- I don't think this - // matters in practice, though. - match this.eq_and_get_goals( - goal.param_env, - goal.predicate.term, - unconstrained_rhs, - ) { - Ok(eq_goals) => { - goals.goals.extend(eq_goals); - } - Err(NoSolution) => return Some(Err(NoSolution)), - }; - - // We only look at the `projection_ty` part here rather than - // looking at the "has changed" return from evaluate_goal, - // because we expect the `unconstrained_rhs` part of the predicate - // to have changed -- that means we actually normalized successfully! - if goal.predicate.projection_ty - != this.resolve_vars_if_possible(goal.predicate.projection_ty) - { - has_changed = Ok(()) - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - // We need to resolve vars here so that we correctly - // deal with `has_changed` in the next iteration. - new_goals.normalizes_to_hack_goal = - Some(this.resolve_vars_if_possible(goal)); - has_changed = has_changed.map_err(|c| c.unify_with(certainty)); - } - } + let mut response = Ok(Certainty::OVERFLOW); + for _ in 0..self.local_overflow_limit() { + // FIXME: This match is a bit ugly, it might be nice to change the inspect + // stuff to use a closure instead. which should hopefully simplify this a bit. + match self.evaluate_added_goals_step() { + Ok(Some(cert)) => { + response = Ok(cert); + break; } - - for goal in goals.goals.drain(..) { - let (changed, certainty, instantiate_goals) = - match this.evaluate_goal(IsNormalizesToHack::No, goal) { - Ok(result) => result, - Err(NoSolution) => return Some(Err(NoSolution)), - }; - new_goals.goals.extend(instantiate_goals); - - if changed { - has_changed = Ok(()); - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - new_goals.goals.push(goal); - has_changed = has_changed.map_err(|c| c.unify_with(certainty)); - } - } + Ok(None) => {} + Err(NoSolution) => { + response = Err(NoSolution); + break; } - - core::mem::swap(&mut new_goals, &mut goals); - match has_changed { - Ok(()) => None, - Err(certainty) => Some(Ok(certainty)), - } - }, - ); + } + } self.inspect.eval_added_goals_result(response); @@ -576,9 +510,84 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { let goal_evaluations = std::mem::replace(&mut self.inspect, inspect); self.inspect.added_goals_evaluation(goal_evaluations); - self.nested_goals = goals; response } + + /// Iterate over all added goals: returning `Ok(Some(_))` in case we can stop rerunning. + /// + /// Goals for the next step get directly added the the nested goals of the `EvalCtxt`. + fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { + let tcx = self.tcx(); + let mut goals = core::mem::replace(&mut self.nested_goals, NestedGoals::new()); + + self.inspect.evaluate_added_goals_loop_start(); + // If this loop did not result in any progress, what's our final certainty. + let mut unchanged_certainty = Some(Certainty::Yes); + if let Some(goal) = goals.normalizes_to_hack_goal.take() { + // Replace the goal with an unconstrained infer var, so the + // RHS does not affect projection candidate assembly. + let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); + let unconstrained_goal = goal.with( + tcx, + ty::ProjectionPredicate { + projection_ty: goal.predicate.projection_ty, + term: unconstrained_rhs, + }, + ); + + let (_, certainty, instantiate_goals) = + self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?; + self.add_goals(instantiate_goals); + + // Finally, equate the goal's RHS with the unconstrained var. + // We put the nested goals from this into goals instead of + // next_goals to avoid needing to process the loop one extra + // time if this goal returns something -- I don't think this + // matters in practice, though. + let eq_goals = + self.eq_and_get_goals(goal.param_env, goal.predicate.term, unconstrained_rhs)?; + goals.goals.extend(eq_goals); + + // We only look at the `projection_ty` part here rather than + // looking at the "has changed" return from evaluate_goal, + // because we expect the `unconstrained_rhs` part of the predicate + // to have changed -- that means we actually normalized successfully! + if goal.predicate.projection_ty + != self.resolve_vars_if_possible(goal.predicate.projection_ty) + { + unchanged_certainty = None; + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + // We need to resolve vars here so that we correctly + // deal with `has_changed` in the next iteration. + self.set_normalizes_to_hack_goal(self.resolve_vars_if_possible(goal)); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } + } + } + + for goal in goals.goals.drain(..) { + let (has_changed, certainty, instantiate_goals) = + self.evaluate_goal(IsNormalizesToHack::No, goal)?; + self.add_goals(instantiate_goals); + if has_changed { + unchanged_certainty = None; + } + + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.add_goal(goal); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } + } + } + + Ok(unchanged_certainty) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -593,10 +602,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } - pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> { - self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) - } - pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> { self.infcx.next_const_var( ty, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 7323b98b8ce..0990b9bee90 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -10,17 +10,21 @@ //! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html use super::{CanonicalInput, Certainty, EvalCtxt, Goal}; use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer}; -use crate::solve::{CanonicalResponse, QueryResult, Response}; +use crate::solve::{response_no_constraints_raw, CanonicalResponse, QueryResult, Response}; use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; +use rustc_infer::infer::InferCtxt; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ - ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, + ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, +}; +use rustc_middle::ty::{ + self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, }; -use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_span::DUMMY_SP; use std::iter; use std::ops::Deref; @@ -32,6 +36,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &self, goal: Goal<'tcx, T>, ) -> (Vec>, CanonicalInput<'tcx, T>) { + let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + let (goal, opaque_types) = + (goal, opaque_types).fold_with(&mut EagerResolver { infcx: self.infcx }); + let mut orig_values = Default::default(); let canonical_goal = Canonicalizer::canonicalize( self.infcx, @@ -40,11 +48,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { QueryInput { goal, anchor: self.infcx.defining_use_anchor, - predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body( - PredefinedOpaquesData { - opaque_types: self.infcx.clone_opaque_types_for_query_response(), - }, - ), + predefined_opaques_in_body: self + .tcx() + .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); (orig_values, canonical_goal) @@ -70,34 +76,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ); let certainty = certainty.unify_with(goals_certainty); + if let Certainty::OVERFLOW = certainty { + // If we have overflow, it's probable that we're substituting a type + // into itself infinitely and any partial substitutions in the query + // response are probably not useful anyways, so just return an empty + // query response. + // + // This may prevent us from potentially useful inference, e.g. + // 2 candidates, one ambiguous and one overflow, which both + // have the same inference constraints. + // + // Changing this to retain some constraints in the future + // won't be a breaking change, so this is good enough for now. + return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow)); + } - let response = match certainty { - Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => { - let external_constraints = self.compute_external_query_constraints()?; - Response { var_values: self.var_values, external_constraints, certainty } - } - Certainty::Maybe(MaybeCause::Overflow) => { - // If we have overflow, it's probable that we're substituting a type - // into itself infinitely and any partial substitutions in the query - // response are probably not useful anyways, so just return an empty - // query response. - // - // This may prevent us from potentially useful inference, e.g. - // 2 candidates, one ambiguous and one overflow, which both - // have the same inference constraints. - // - // Changing this to retain some constraints in the future - // won't be a breaking change, so this is good enough for now. - return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow)); - } - }; + let var_values = self.var_values; + let external_constraints = self.compute_external_query_constraints()?; + + let (var_values, mut external_constraints) = + (var_values, external_constraints).fold_with(&mut EagerResolver { infcx: self.infcx }); + // Remove any trivial region constraints once we've resolved regions + external_constraints + .region_constraints + .outlives + .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( self.infcx, CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, &mut Default::default(), - response, + Response { + var_values, + certainty, + external_constraints: self.tcx().mk_external_constraints(external_constraints), + }, ); + Ok(canonical) } @@ -109,29 +124,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &self, maybe_cause: MaybeCause, ) -> CanonicalResponse<'tcx> { - let unconstrained_response = Response { - var_values: CanonicalVarValues { - var_values: self.tcx().mk_args_from_iter(self.var_values.var_values.iter().map( - |arg| -> ty::GenericArg<'tcx> { - match arg.unpack() { - GenericArgKind::Lifetime(_) => self.next_region_infer().into(), - GenericArgKind::Type(_) => self.next_ty_infer().into(), - GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(), - } - }, - )), - }, - external_constraints: self - .tcx() - .mk_external_constraints(ExternalConstraintsData::default()), - certainty: Certainty::Maybe(maybe_cause), - }; - - Canonicalizer::canonicalize( - self.infcx, - CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, - &mut Default::default(), - unconstrained_response, + response_no_constraints_raw( + self.tcx(), + self.max_input_universe, + self.variables, + Certainty::Maybe(maybe_cause), ) } @@ -143,7 +140,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// further constrained by inference, that will be passed back in the var /// values. #[instrument(level = "debug", skip(self), ret)] - fn compute_external_query_constraints(&self) -> Result, NoSolution> { + fn compute_external_query_constraints( + &self, + ) -> Result, NoSolution> { // We only check for leaks from universes which were entered inside // of the query. self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { @@ -173,9 +172,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) }); - Ok(self - .tcx() - .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) + Ok(ExternalConstraintsData { region_constraints, opaque_types }) } /// After calling a canonical query, we apply the constraints returned @@ -333,3 +330,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(()) } } + +/// Resolves ty, region, and const vars to their inferred values or their root vars. +struct EagerResolver<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, +} + +impl<'tcx> TypeFolder> for EagerResolver<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match *t.kind() { + ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) { + Ok(t) => t.fold_with(self), + Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)), + }, + ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid), + ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid), + _ => { + if t.has_infer() { + t.super_fold_with(self) + } else { + t + } + } + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReVar(vid) => self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.infcx.tcx, vid), + _ => r, + } + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + match c.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + // FIXME: we need to fold the ty too, I think. + match self.infcx.probe_const_var(vid) { + Ok(c) => c.fold_with(self), + Err(_) => { + ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty()) + } + } + } + _ => { + if c.has_infer() { + c.super_fold_with(self) + } else { + c + } + } + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index 4477ea7d501..317c43baf8f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -17,6 +17,7 @@ where let mut nested_ecx = EvalCtxt { infcx: outer_ecx.infcx, + variables: outer_ecx.variables, var_values: outer_ecx.var_values, predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, max_input_universe: outer_ecx.max_input_universe, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 8a3c7b22e32..ca4a4c9510c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -14,7 +14,6 @@ use rustc_span::DUMMY_SP; use crate::solve::assembly::{Candidate, CandidateSource}; use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree}; use crate::solve::inspect::ProofTreeBuilder; -use crate::solve::search_graph::OverflowHandler; use crate::traits::StructurallyNormalizeExt; use crate::traits::TraitEngineExt; @@ -143,7 +142,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // the cycle anyways one step later. EvalCtxt::enter_canonical( self.tcx(), - self.search_graph(), + self.search_graph, canonical_input, // FIXME: This is wrong, idk if we even want to track stuff here. &mut ProofTreeBuilder::new_noop(), @@ -269,7 +268,7 @@ fn rematch_unsize<'tcx>( infcx.tcx, ObligationCause::dummy(), goal.param_env, - ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)), + ty::OutlivesPredicate(a_ty, region), )); Ok(Some(ImplSource::Builtin(source, nested))) diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 63e48c94a86..63d4a38119f 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -17,10 +17,11 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; +use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate, }; @@ -284,20 +285,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } -pub(super) fn response_no_constraints<'tcx>( +fn response_no_constraints_raw<'tcx>( tcx: TyCtxt<'tcx>, - goal: Canonical<'tcx, impl Sized>, + max_universe: UniverseIndex, + variables: CanonicalVarInfos<'tcx>, certainty: Certainty, -) -> QueryResult<'tcx> { - Ok(Canonical { - max_universe: goal.max_universe, - variables: goal.variables, +) -> CanonicalResponse<'tcx> { + Canonical { + max_universe, + variables, value: Response { - var_values: CanonicalVarValues::make_identity(tcx, goal.variables), + var_values: CanonicalVarValues::make_identity(tcx, variables), // FIXME: maybe we should store the "no response" version in tcx, like // we do for tcx.types and stuff. external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), certainty, }, - }) + } } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 091b7f33834..872f0c87916 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -75,10 +75,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { tcx, self.at.cause.clone(), self.at.param_env, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty: alias, - term: new_infer_ty.into(), - }), + ty::ProjectionPredicate { projection_ty: alias, term: new_infer_ty.into() }, ); // Do not emit an error if normalization is known to fail but instead @@ -131,10 +128,10 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { tcx, self.at.cause.clone(), self.at.param_env, - ty::Binder::dummy(ty::ProjectionPredicate { + ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(uv.def, uv.args), term: new_infer_ct.into(), - }), + }, ); let result = if infcx.predicate_may_hold(&obligation) { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 2ce57751740..75cf33d8194 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -393,10 +393,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { None => tcx.types.unit, Some(field_def) => { let self_ty = field_def.ty(tcx, args); - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - )); + ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty))); return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } @@ -406,10 +403,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ty::Tuple(elements) => match elements.last() { None => tcx.types.unit, Some(&self_ty) => { - ecx.add_goal(goal.with( - tcx, - ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)), - )); + ecx.add_goal(goal.with(tcx, goal.predicate.with_self_ty(tcx, self_ty))); return ecx .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } @@ -450,10 +444,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { Self::consider_implied_clause( ecx, goal, - ty::Binder::dummy(ty::ProjectionPredicate { + ty::ProjectionPredicate { projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]), term, - }) + } .to_predicate(tcx), // Technically, we need to check that the future type is Sized, // but that's already proven by the generator being WF. @@ -490,12 +484,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { Self::consider_implied_clause( ecx, goal, - ty::Binder::dummy(ty::ProjectionPredicate { + ty::ProjectionPredicate { projection_ty: ecx .tcx() .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), term, - }) + } .to_predicate(tcx), // Technically, we need to check that the future type is Sized, // but that's already proven by the generator being WF. diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index c25d6eca918..21c8d476902 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -1,37 +1,51 @@ mod cache; -mod overflow; - -pub(super) use overflow::OverflowHandler; -use rustc_middle::traits::solve::inspect::CacheHit; use self::cache::ProvisionalEntry; -use cache::ProvisionalCache; -use overflow::OverflowData; -use rustc_index::IndexVec; -use rustc_middle::dep_graph::DepKind; -use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; -use rustc_middle::ty::TyCtxt; -use std::{collections::hash_map::Entry, mem}; - use super::inspect::ProofTreeBuilder; use super::SolverMode; +use cache::ProvisionalCache; +use rustc_data_structures::fx::FxHashSet; +use rustc_index::Idx; +use rustc_index::IndexVec; +use rustc_middle::dep_graph::DepKind; +use rustc_middle::traits::solve::inspect::CacheHit; +use rustc_middle::traits::solve::CacheData; +use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult}; +use rustc_middle::ty::TyCtxt; +use rustc_session::Limit; +use std::{collections::hash_map::Entry, mem}; rustc_index::newtype_index! { pub struct StackDepth {} } -struct StackElem<'tcx> { +#[derive(Debug)] +struct StackEntry<'tcx> { input: CanonicalInput<'tcx>, + available_depth: Limit, + // The maximum depth reached by this stack entry, only up-to date + // for the top of the stack and lazily updated for the rest. + reached_depth: StackDepth, + encountered_overflow: bool, has_been_used: bool, + + /// We put only the root goal of a coinductive cycle into the global cache. + /// + /// If we were to use that result when later trying to prove another cycle + /// participant, we can end up with unstable query results. + /// + /// See tests/ui/new-solver/coinduction/incompleteness-unstable-result.rs for + /// an example of where this is needed. + cycle_participants: FxHashSet>, } pub(super) struct SearchGraph<'tcx> { mode: SolverMode, + local_overflow_limit: usize, /// The stack of goals currently being computed. /// /// An element is *deeper* in the stack if its index is *lower*. - stack: IndexVec>, - overflow_data: OverflowData, + stack: IndexVec>, provisional_cache: ProvisionalCache<'tcx>, } @@ -39,8 +53,8 @@ impl<'tcx> SearchGraph<'tcx> { pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { Self { mode, + local_overflow_limit: tcx.recursion_limit().0.ilog2() as usize, stack: Default::default(), - overflow_data: OverflowData::new(tcx), provisional_cache: ProvisionalCache::empty(), } } @@ -49,15 +63,38 @@ impl<'tcx> SearchGraph<'tcx> { self.mode } - /// We do not use the global cache during coherence. + pub(super) fn local_overflow_limit(&self) -> usize { + self.local_overflow_limit + } + + /// Update the stack and reached depths on cache hits. + #[instrument(level = "debug", skip(self))] + fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) { + let reached_depth = self.stack.next_index().plus(additional_depth); + if let Some(last) = self.stack.raw.last_mut() { + last.reached_depth = last.reached_depth.max(reached_depth); + last.encountered_overflow |= encountered_overflow; + } + } + + /// Pops the highest goal from the stack, lazily updating the + /// the next goal in the stack. /// + /// Directly popping from the stack instead of using this method + /// would cause us to not track overflow and recursion depth correctly. + fn pop_stack(&mut self) -> StackEntry<'tcx> { + let elem = self.stack.pop().unwrap(); + if let Some(last) = self.stack.raw.last_mut() { + last.reached_depth = last.reached_depth.max(elem.reached_depth); + last.encountered_overflow |= elem.encountered_overflow; + } + elem + } + /// The trait solver behavior is different for coherence - /// so we would have to add the solver mode to the cache key. - /// This is probably not worth it as trait solving during - /// coherence tends to already be incredibly fast. - /// - /// We could add another global cache for coherence instead, - /// but that's effort so let's only do it if necessary. + /// so we use a separate cache. Alternatively we could use + /// a single cache and share it between coherence and ordinary + /// trait solving. pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> { match self.mode { SolverMode::Normal => &tcx.new_solver_evaluation_cache, @@ -87,36 +124,107 @@ impl<'tcx> SearchGraph<'tcx> { } } - /// Tries putting the new goal on the stack, returning an error if it is already cached. + /// Fetches whether the current goal encountered overflow. /// - /// This correctly updates the provisional cache if there is a cycle. - #[instrument(level = "debug", skip(self, tcx, inspect), ret)] - fn try_push_stack( + /// This should only be used for the check in `evaluate_goal`. + pub(super) fn encountered_overflow(&self) -> bool { + if let Some(last) = self.stack.raw.last() { last.encountered_overflow } else { false } + } + + /// Resets `encountered_overflow` of the current goal. + /// + /// This should only be used for the check in `evaluate_goal`. + pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) { + if encountered_overflow { + self.stack.raw.last_mut().unwrap().encountered_overflow = true; + } + } + + /// Returns the remaining depth allowed for nested goals. + /// + /// This is generally simply one less than the current depth. + /// However, if we encountered overflow, we significantly reduce + /// the remaining depth of all nested goals to prevent hangs + /// in case there is exponential blowup. + fn allowed_depth_for_nested( + tcx: TyCtxt<'tcx>, + stack: &IndexVec>, + ) -> Option { + if let Some(last) = stack.raw.last() { + if last.available_depth.0 == 0 { + return None; + } + + Some(if last.encountered_overflow { + Limit(last.available_depth.0 / 4) + } else { + Limit(last.available_depth.0 - 1) + }) + } else { + Some(tcx.recursion_limit()) + } + } + + /// Probably the most involved method of the whole solver. + /// + /// Given some goal which is proven via the `prove_goal` closure, this + /// handles caching, overflow, and coinductive cycles. + pub(super) fn with_new_goal( &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<'tcx>, inspect: &mut ProofTreeBuilder<'tcx>, - ) -> Result<(), QueryResult<'tcx>> { - // Look at the provisional cache to check for cycles. + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, + ) -> QueryResult<'tcx> { + // Check for overflow. + let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { + if let Some(last) = self.stack.raw.last_mut() { + last.encountered_overflow = true; + } + return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); + }; + + // Try to fetch the goal from the global cache. + if inspect.use_global_cache() { + if let Some(CacheData { result, reached_depth, encountered_overflow }) = + self.global_cache(tcx).get( + tcx, + input, + |cycle_participants| { + self.stack.iter().any(|entry| cycle_participants.contains(&entry.input)) + }, + available_depth, + ) + { + self.on_cache_hit(reached_depth, encountered_overflow); + return result; + } + } + + // Look at the provisional cache to detect cycles. let cache = &mut self.provisional_cache; match cache.lookup_table.entry(input) { - // No entry, simply push this goal on the stack after dealing with overflow. + // No entry, we push this goal on the stack and try to prove it. Entry::Vacant(v) => { - if self.overflow_data.has_overflow(self.stack.len()) { - return Err(self.deal_with_overflow(tcx, input)); - } - - let depth = self.stack.push(StackElem { input, has_been_used: false }); - let response = super::response_no_constraints(tcx, input, Certainty::Yes); + let depth = self.stack.next_index(); + let entry = StackEntry { + input, + available_depth, + reached_depth: depth, + encountered_overflow: false, + has_been_used: false, + cycle_participants: Default::default(), + }; + assert_eq!(self.stack.push(entry), depth); + let response = Self::response_no_constraints(tcx, input, Certainty::Yes); let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input }); v.insert(entry_index); - Ok(()) } // We have a nested goal which relies on a goal `root` deeper in the stack. // - // We first store that we may have to rerun `evaluate_goal` for `root` in case the - // provisional response is not equal to the final response. We also update the depth - // of all goals which recursively depend on our current goal to depend on `root` + // We first store that we may have to reprove `root` in case the provisional + // response is not equal to the final response. We also update the depth of all + // goals which recursively depend on our current goal to depend on `root` // instead. // // Finally we can return either the provisional response for that goal if we have a @@ -125,13 +233,16 @@ impl<'tcx> SearchGraph<'tcx> { inspect.cache_hit(CacheHit::Provisional); let entry_index = *entry_index.get(); - let stack_depth = cache.depth(entry_index); debug!("encountered cycle with depth {stack_depth:?}"); cache.add_dependency_of_leaf_on(entry_index); + let mut iter = self.stack.iter_mut(); + let root = iter.nth(stack_depth.as_usize()).unwrap(); + for e in iter { + root.cycle_participants.insert(e.input); + } - self.stack[stack_depth].has_been_used = true; // NOTE: The goals on the stack aren't the only goals involved in this cycle. // We can also depend on goals which aren't part of the stack but coinductively // depend on the stack themselves. We already checked whether all the goals @@ -142,145 +253,111 @@ impl<'tcx> SearchGraph<'tcx> { .iter() .all(|g| g.input.value.goal.predicate.is_coinductive(tcx)) { - Err(cache.provisional_result(entry_index)) + // If we're in a coinductive cycle, we have to retry proving the current goal + // until we reach a fixpoint. + self.stack[stack_depth].has_been_used = true; + return cache.provisional_result(entry_index); } else { - Err(super::response_no_constraints(tcx, input, Certainty::OVERFLOW)) + return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); } } } - } - /// We cannot simply store the result of [super::EvalCtxt::compute_goal] as we have to deal with - /// coinductive cycles. - /// - /// When we encounter a coinductive cycle, we have to prove the final result of that cycle - /// while we are still computing that result. Because of this we continuously recompute the - /// cycle until the result of the previous iteration is equal to the final result, at which - /// point we are done. - /// - /// This function returns `true` if we were able to finalize the goal and `false` if it has - /// updated the provisional cache and we have to recompute the current goal. - /// - /// FIXME: Refer to the rustc-dev-guide entry once it exists. - #[instrument(level = "debug", skip(self, actual_input), ret)] - fn try_finalize_goal( - &mut self, - actual_input: CanonicalInput<'tcx>, - response: QueryResult<'tcx>, - ) -> bool { - let stack_elem = self.stack.pop().unwrap(); - let StackElem { input, has_been_used } = stack_elem; - assert_eq!(input, actual_input); + // This is for global caching, so we properly track query dependencies. + // Everything that affects the `result` should be performed within this + // `with_anon_task` closure. + let ((final_entry, result), dep_node) = + tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || { + // When we encounter a coinductive cycle, we have to fetch the + // result of that cycle while we are still computing it. Because + // of this we continuously recompute the cycle until the result + // of the previous iteration is equal to the final result, at which + // point we are done. + for _ in 0..self.local_overflow_limit() { + let response = prove_goal(self, inspect); + // Check whether the current goal is the root of a cycle and whether + // we have to rerun because its provisional result differed from the + // final result. + // + // Also update the response for this goal stored in the provisional + // cache. + let stack_entry = self.pop_stack(); + debug_assert_eq!(stack_entry.input, input); + let cache = &mut self.provisional_cache; + let provisional_entry_index = + *cache.lookup_table.get(&stack_entry.input).unwrap(); + let provisional_entry = &mut cache.entries[provisional_entry_index]; + let prev_response = mem::replace(&mut provisional_entry.response, response); + if stack_entry.has_been_used && prev_response != response { + // If so, remove all entries whose result depends on this goal + // from the provisional cache... + // + // That's not completely correct, as a nested goal can also + // depend on a goal which is lower in the stack so it doesn't + // actually depend on the current goal. This should be fairly + // rare and is hopefully not relevant for performance. + #[allow(rustc::potential_query_instability)] + cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index); + cache.entries.truncate(provisional_entry_index.index() + 1); + + // ...and finally push our goal back on the stack and reevaluate it. + self.stack.push(StackEntry { has_been_used: false, ..stack_entry }); + } else { + return (stack_entry, response); + } + } + + debug!("canonical cycle overflow"); + let current_entry = self.pop_stack(); + let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); + (current_entry, result) + }); + + // We're now done with this goal. In case this goal is involved in a larger cycle + // do not remove it from the provisional cache and do not add it to the global + // cache. + // + // It is not possible for any nested goal to depend on something deeper on the + // stack, as this would have also updated the depth of the current goal. let cache = &mut self.provisional_cache; let provisional_entry_index = *cache.lookup_table.get(&input).unwrap(); let provisional_entry = &mut cache.entries[provisional_entry_index]; - // We eagerly update the response in the cache here. If we have to reevaluate - // this goal we use the new response when hitting a cycle, and we definitely - // want to access the final response whenever we look at the cache. - let prev_response = mem::replace(&mut provisional_entry.response, response); - - // Was the current goal the root of a cycle and was the provisional response - // different from the final one. - if has_been_used && prev_response != response { - // If so, remove all entries whose result depends on this goal - // from the provisional cache... - // - // That's not completely correct, as a nested goal can also - // depend on a goal which is lower in the stack so it doesn't - // actually depend on the current goal. This should be fairly - // rare and is hopefully not relevant for performance. - #[allow(rustc::potential_query_instability)] - cache.lookup_table.retain(|_key, index| *index <= provisional_entry_index); - cache.entries.truncate(provisional_entry_index.index() + 1); - - // ...and finally push our goal back on the stack and reevaluate it. - self.stack.push(StackElem { input, has_been_used: false }); - false - } else { - true - } - } - - pub(super) fn with_new_goal( - &mut self, - tcx: TyCtxt<'tcx>, - canonical_input: CanonicalInput<'tcx>, - inspect: &mut ProofTreeBuilder<'tcx>, - mut loop_body: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>, - ) -> QueryResult<'tcx> { - if inspect.use_global_cache() { - if let Some(result) = self.global_cache(tcx).get(&canonical_input, tcx) { - debug!(?canonical_input, ?result, "cache hit"); - inspect.cache_hit(CacheHit::Global); - return result; - } - } - - match self.try_push_stack(tcx, canonical_input, inspect) { - Ok(()) => {} - // Our goal is already on the stack, eager return. - Err(response) => return response, - } - - // This is for global caching, so we properly track query dependencies. - // Everything that affects the `Result` should be performed within this - // `with_anon_task` closure. - let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || { - self.repeat_while_none( - |this| { - let result = this.deal_with_overflow(tcx, canonical_input); - let _ = this.stack.pop().unwrap(); - result - }, - |this| { - let result = loop_body(this, inspect); - this.try_finalize_goal(canonical_input, result).then(|| result) - }, - ) - }); - - let cache = &mut self.provisional_cache; - let provisional_entry_index = *cache.lookup_table.get(&canonical_input).unwrap(); - let provisional_entry = &mut cache.entries[provisional_entry_index]; let depth = provisional_entry.depth; - - // If not, we're done with this goal. - // - // Check whether that this goal doesn't depend on a goal deeper on the stack - // and if so, move it to the global cache. - // - // Note that if any nested goal were to depend on something deeper on the stack, - // this would have also updated the depth of the current goal. if depth == self.stack.next_index() { - // If the current goal is the head of a cycle, we drop all other - // cycle participants without moving them to the global cache. - let other_cycle_participants = provisional_entry_index.index() + 1; - for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) { + for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) { let actual_index = cache.lookup_table.remove(&entry.input); debug_assert_eq!(Some(i), actual_index); debug_assert!(entry.depth == depth); } - let current_goal = cache.entries.pop().unwrap(); - let actual_index = cache.lookup_table.remove(¤t_goal.input); - debug_assert_eq!(Some(provisional_entry_index), actual_index); - debug_assert!(current_goal.depth == depth); - - // We move the root goal to the global cache if we either did not hit an overflow or if it's - // the root goal as that will now always hit the same overflow limit. + // When encountering a cycle, both inductive and coinductive, we only + // move the root into the global cache. We also store all other cycle + // participants involved. // - // NOTE: We cannot move any non-root goals to the global cache. When replaying the root goal's - // dependencies, our non-root goal may no longer appear as child of the root goal. - // - // See https://github.com/rust-lang/rust/pull/108071 for some additional context. - let can_cache = inspect.use_global_cache() - && (!self.overflow_data.did_overflow() || self.stack.is_empty()); - if can_cache { - self.global_cache(tcx).insert(current_goal.input, dep_node, current_goal.response) - } + // We disable the global cache entry of the root goal if a cycle + // participant is on the stack. This is necessary to prevent unstable + // results. See the comment of `StackEntry::cycle_participants` for + // more details. + let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len(); + self.global_cache(tcx).insert( + input, + reached_depth, + final_entry.encountered_overflow, + final_entry.cycle_participants, + dep_node, + result, + ) } result } + + fn response_no_constraints( + tcx: TyCtxt<'tcx>, + goal: CanonicalInput<'tcx>, + certainty: Certainty, + ) -> QueryResult<'tcx> { + Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty)) + } } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs b/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs deleted file mode 100644 index 83a051eeb1a..00000000000 --- a/compiler/rustc_trait_selection/src/solve/search_graph/overflow.rs +++ /dev/null @@ -1,120 +0,0 @@ -use rustc_infer::infer::canonical::Canonical; -use rustc_infer::traits::query::NoSolution; -use rustc_middle::traits::solve::{Certainty, QueryResult}; -use rustc_middle::ty::TyCtxt; -use rustc_session::Limit; - -use super::SearchGraph; -use crate::solve::{response_no_constraints, EvalCtxt}; - -/// When detecting a solver overflow, we return ambiguity. Overflow can be -/// *hidden* by either a fatal error in an **AND** or a trivial success in an **OR**. -/// -/// This is in issue in case of exponential blowup, e.g. if each goal on the stack -/// has multiple nested (overflowing) candidates. To deal with this, we reduce the limit -/// used by the solver when hitting the default limit for the first time. -/// -/// FIXME: Get tests where always using the `default_limit` results in a hang and refer -/// to them here. We can also improve the overflow strategy if necessary. -pub(super) struct OverflowData { - default_limit: Limit, - current_limit: Limit, - /// When proving an **AND** we have to repeatedly iterate over the yet unproven goals. - /// - /// Because of this each iteration also increases the depth in addition to the stack - /// depth. - additional_depth: usize, -} - -impl OverflowData { - pub(super) fn new(tcx: TyCtxt<'_>) -> OverflowData { - let default_limit = tcx.recursion_limit(); - OverflowData { default_limit, current_limit: default_limit, additional_depth: 0 } - } - - #[inline] - pub(super) fn did_overflow(&self) -> bool { - self.default_limit.0 != self.current_limit.0 - } - - #[inline] - pub(super) fn has_overflow(&self, depth: usize) -> bool { - !self.current_limit.value_within_limit(depth + self.additional_depth) - } - - /// Updating the current limit when hitting overflow. - fn deal_with_overflow(&mut self) { - // When first hitting overflow we reduce the overflow limit - // for all future goals to prevent hangs if there's an exponential - // blowup. - self.current_limit.0 = self.default_limit.0 / 8; - } -} - -pub(in crate::solve) trait OverflowHandler<'tcx> { - fn search_graph(&mut self) -> &mut SearchGraph<'tcx>; - - fn repeat_while_none( - &mut self, - on_overflow: impl FnOnce(&mut Self) -> Result, - mut loop_body: impl FnMut(&mut Self) -> Option>, - ) -> Result { - let start_depth = self.search_graph().overflow_data.additional_depth; - let depth = self.search_graph().stack.len(); - while !self.search_graph().overflow_data.has_overflow(depth) { - if let Some(result) = loop_body(self) { - self.search_graph().overflow_data.additional_depth = start_depth; - return result; - } - - self.search_graph().overflow_data.additional_depth += 1; - } - self.search_graph().overflow_data.additional_depth = start_depth; - self.search_graph().overflow_data.deal_with_overflow(); - on_overflow(self) - } - - // Increment the `additional_depth` by one and evaluate `body`, or `on_overflow` - // if the depth is overflown. - fn with_incremented_depth( - &mut self, - on_overflow: impl FnOnce(&mut Self) -> T, - body: impl FnOnce(&mut Self) -> T, - ) -> T { - let depth = self.search_graph().stack.len(); - self.search_graph().overflow_data.additional_depth += 1; - - let result = if self.search_graph().overflow_data.has_overflow(depth) { - self.search_graph().overflow_data.deal_with_overflow(); - on_overflow(self) - } else { - body(self) - }; - - self.search_graph().overflow_data.additional_depth -= 1; - result - } -} - -impl<'tcx> OverflowHandler<'tcx> for EvalCtxt<'_, 'tcx> { - fn search_graph(&mut self) -> &mut SearchGraph<'tcx> { - &mut self.search_graph - } -} - -impl<'tcx> OverflowHandler<'tcx> for SearchGraph<'tcx> { - fn search_graph(&mut self) -> &mut SearchGraph<'tcx> { - self - } -} - -impl<'tcx> SearchGraph<'tcx> { - pub fn deal_with_overflow( - &mut self, - tcx: TyCtxt<'tcx>, - goal: Canonical<'tcx, impl Sized>, - ) -> QueryResult<'tcx> { - self.overflow_data.deal_with_overflow(); - response_no_constraints(tcx, goal, Certainty::OVERFLOW) - } -} diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 14a5b9656e5..db80b62d8a2 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,7 +1,6 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. use super::assembly::{self, structural_traits}; -use super::search_graph::OverflowHandler; use super::{EvalCtxt, SolverMode}; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; @@ -444,7 +443,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { Err(NoSolution) => vec![], }; - ecx.probe(|_| CandidateKind::DynUpcastingAssembly).enter(|ecx| { + ecx.probe(|_| CandidateKind::UnsizeAssembly).enter(|ecx| { let a_ty = goal.predicate.self_ty(); // We need to normalize the b_ty since it's matched structurally // in the other functions below. @@ -526,7 +525,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { b_region: ty::Region<'tcx>, ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> { let tcx = self.tcx(); - let Goal { predicate: (a_ty, b_ty), .. } = goal; + let Goal { predicate: (a_ty, _b_ty), .. } = goal; // All of a's auto traits need to be in b's auto traits. let auto_traits_compatible = @@ -535,51 +534,30 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return vec![]; } - // Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with - // the supertrait principal and subtyping the types. - let unsize_dyn_to_principal = - |ecx: &mut Self, principal: Option>| { - ecx.probe_candidate("upcast dyn to principle").enter( - |ecx| -> Result<_, NoSolution> { - // Require that all of the trait predicates from A match B, except for - // the auto traits. We do this by constructing a new A type with B's - // auto traits, and equating these types. - let new_a_data = principal - .into_iter() - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) - .chain(a_data.iter().filter(|a| { - matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) - })) - .chain( - b_data - .auto_traits() - .map(ty::ExistentialPredicate::AutoTrait) - .map(ty::Binder::dummy), - ); - let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); - let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn); - - // We also require that A's lifetime outlives B's lifetime. - ecx.eq(goal.param_env, new_a_ty, b_ty)?; - ecx.add_goal(goal.with(tcx, ty::OutlivesPredicate(a_region, b_region))); - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - }, - ) - }; - let mut responses = vec![]; // If the principal def ids match (or are both none), then we're not doing // trait upcasting. We're just removing auto traits (or shortening the lifetime). if a_data.principal_def_id() == b_data.principal_def_id() { - if let Ok(resp) = unsize_dyn_to_principal(self, a_data.principal()) { + if let Ok(resp) = self.consider_builtin_upcast_to_principal( + goal, + a_data, + a_region, + b_data, + b_region, + a_data.principal(), + ) { responses.push((resp, BuiltinImplSource::Misc)); } } else if let Some(a_principal) = a_data.principal() { self.walk_vtable( a_principal.with_self_ty(tcx, a_ty), |ecx, new_a_principal, _, vtable_vptr_slot| { - if let Ok(resp) = unsize_dyn_to_principal( - ecx, + if let Ok(resp) = ecx.consider_builtin_upcast_to_principal( + goal, + a_data, + a_region, + b_data, + b_region, Some(new_a_principal.map_bound(|trait_ref| { ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) })), @@ -631,6 +609,83 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + fn consider_builtin_upcast_to_principal( + &mut self, + goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, + a_data: &'tcx ty::List>, + a_region: ty::Region<'tcx>, + b_data: &'tcx ty::List>, + b_region: ty::Region<'tcx>, + upcast_principal: Option>, + ) -> QueryResult<'tcx> { + let param_env = goal.param_env; + + // More than one projection in a_ty's bounds may match the projection + // in b_ty's bound. Use this to first determine *which* apply without + // having any inference side-effects. We process obligations because + // unification may initially succeed due to deferred projection equality. + let projection_may_match = + |ecx: &mut Self, + source_projection: ty::PolyExistentialProjection<'tcx>, + target_projection: ty::PolyExistentialProjection<'tcx>| { + source_projection.item_def_id() == target_projection.item_def_id() + && ecx + .probe(|_| CandidateKind::UpcastProbe) + .enter(|ecx| -> Result<(), NoSolution> { + ecx.eq(param_env, source_projection, target_projection)?; + let _ = ecx.try_evaluate_added_goals()?; + Ok(()) + }) + .is_ok() + }; + + for bound in b_data { + match bound.skip_binder() { + // Check that a's supertrait (upcast_principal) is compatible + // with the target (b_ty). + ty::ExistentialPredicate::Trait(target_principal) => { + self.eq(param_env, upcast_principal.unwrap(), bound.rebind(target_principal))?; + } + // Check that b_ty's projection is satisfied by exactly one of + // a_ty's projections. First, we look through the list to see if + // any match. If not, error. Then, if *more* than one matches, we + // return ambiguity. Otherwise, if exactly one matches, equate + // it with b_ty's projection. + ty::ExistentialPredicate::Projection(target_projection) => { + let target_projection = bound.rebind(target_projection); + let mut matching_projections = + a_data.projection_bounds().filter(|source_projection| { + projection_may_match(self, *source_projection, target_projection) + }); + let Some(source_projection) = matching_projections.next() else { + return Err(NoSolution); + }; + if matching_projections.next().is_some() { + return self.evaluate_added_goals_and_make_canonical_response( + Certainty::AMBIGUOUS, + ); + } + self.eq(param_env, source_projection, target_projection)?; + } + // Check that b_ty's auto traits are present in a_ty's bounds. + ty::ExistentialPredicate::AutoTrait(def_id) => { + if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + return Err(NoSolution); + } + } + } + } + + // Also require that a_ty's lifetime outlives b_ty's lifetime. + self.add_goal(Goal::new( + self.tcx(), + param_env, + ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), + )); + + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + /// We have the following builtin impls for arrays: /// ```ignore (builtin impl example) /// impl Unsize<[T]> for [T; N] {} @@ -857,12 +912,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ecx.add_goals( constituent_tys(ecx, goal.predicate.self_ty())? .into_iter() - .map(|ty| { - goal.with( - ecx.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)), - ) - }) + .map(|ty| goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty))) .collect::>(), ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -879,7 +929,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } /// Normalize a non-self type when it is structually matched on when solving - /// a built-in goal. This is handled already through `assemble_candidates_after_normalizing_self_ty` + /// a built-in goal. + /// + /// This is handled already through `assemble_candidates_after_normalizing_self_ty` /// for the self type, but for other goals, additional normalization of other /// arguments may be needed to completely implement the semantics of the trait. /// @@ -894,30 +946,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { return Ok(Some(ty)); } - self.repeat_while_none( - |_| Ok(None), - |ecx| { - let ty::Alias(_, projection_ty) = *ty.kind() else { - return Some(Ok(Some(ty))); - }; + for _ in 0..self.local_overflow_limit() { + let ty::Alias(_, projection_ty) = *ty.kind() else { + return Ok(Some(ty)); + }; - let normalized_ty = ecx.next_ty_infer(); - let normalizes_to_goal = Goal::new( - ecx.tcx(), - param_env, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: normalized_ty.into(), - }), - ); - ecx.add_goal(normalizes_to_goal); - if let Err(err) = ecx.try_evaluate_added_goals() { - return Some(Err(err)); - } + let normalized_ty = self.next_ty_infer(); + let normalizes_to_goal = Goal::new( + self.tcx(), + param_env, + ty::ProjectionPredicate { projection_ty, term: normalized_ty.into() }, + ); + self.add_goal(normalizes_to_goal); + self.try_evaluate_added_goals()?; + ty = self.resolve_vars_if_possible(normalized_ty); + } - ty = ecx.resolve_vars_if_possible(normalized_ty); - None - }, - ) + Ok(None) } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index eae13eb6302..4d85e2b6089 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2987,6 +2987,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { unsatisfied_const: bool, ) { let body_def_id = obligation.cause.body_id; + let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } = + obligation.cause.code() + { + *rhs_span + } else { + span + }; + // Try to report a help message if is_fn_trait && let Ok((implemented_kind, params)) = self.type_implements_fn_trait( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 46c31c77613..1c59f3ff6c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2789,7 +2789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // implement this trait and list them. err.note(format!( "`{short_item_name}` is a \"sealed trait\", because to implement \ - it you also need to implelement `{}`, which is not accessible; \ + it you also need to implement `{}`, which is not accessible; \ this is usually done to force you to use one of the provided \ types that already implement it", with_no_trimmed_paths!(tcx.def_path_str(def_id)), @@ -2854,7 +2854,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all local variables must have a statically known size"); } Some(Node::Local(hir::Local { - init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), + init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }), .. })) => { // When encountering an assignment of an unsized trait, like @@ -3953,9 +3953,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { - // We can only suggest the slice coersion for function arguments since the suggestion - // would make no sense in turbofish or call - let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else { + // We can only suggest the slice coersion for function and binary operation arguments, + // since the suggestion would make no sense in turbofish or call + let (ObligationCauseCode::BinOp { .. } + | ObligationCauseCode::FunctionArgumentObligation { .. }) = obligation.cause.code() + else { return; }; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 8f2f02a5e41..e3da87a2210 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -745,7 +745,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => { + ( + &ty::Dynamic(ref a_data, a_region, ty::Dyn), + &ty::Dynamic(ref b_data, b_region, ty::Dyn), + ) => { // Upcast coercions permit several things: // // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` @@ -757,19 +760,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // We always perform upcasting coercions when we can because of reason // #2 (region bounds). - let auto_traits_compatible = data_b + let auto_traits_compatible = b_data .auto_traits() // All of a's auto traits need to be in b's auto traits. - .all(|b| data_a.auto_traits().any(|a| a == b)); + .all(|b| a_data.auto_traits().any(|a| a == b)); if auto_traits_compatible { - let principal_def_id_a = data_a.principal_def_id(); - let principal_def_id_b = data_b.principal_def_id(); + let principal_def_id_a = a_data.principal_def_id(); + let principal_def_id_b = b_data.principal_def_id(); if principal_def_id_a == principal_def_id_b { // no cyclic candidates.vec.push(BuiltinUnsizeCandidate); } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { // not casual unsizing, now check whether this is trait upcasting coercion. - let principal_a = data_a.principal().unwrap(); + let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( @@ -785,9 +788,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() { - if upcast_trait_ref.def_id() == target_trait_did { - candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); - } + self.infcx.probe(|_| { + if upcast_trait_ref.def_id() == target_trait_did + && let Ok(nested) = self.match_upcast_principal( + obligation, + upcast_trait_ref, + a_data, + b_data, + a_region, + b_region, + ) + { + if nested.is_none() { + candidates.ambiguous = true; + } + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + } + }) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index cf9d2bda17e..71a82baeec6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -879,68 +879,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `assemble_candidates_for_unsizing` should ensure there are no late-bound // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); - let target = self.infcx.shallow_resolve(target); + let predicate = obligation.predicate.no_bound_vars().unwrap(); + let a_ty = self.infcx.shallow_resolve(predicate.self_ty()); + let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1)); - debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate"); + let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { bug!() }; + let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() }; - let mut nested = vec![]; - let source_trait_ref; - let upcast_trait_ref; - match (source.kind(), target.kind()) { - // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). - ( - &ty::Dynamic(ref data_a, r_a, repr_a @ ty::Dyn), - &ty::Dynamic(ref data_b, r_b, ty::Dyn), - ) => { - // See `assemble_candidates_for_unsizing` for more info. - // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. - let principal_a = data_a.principal().unwrap(); - source_trait_ref = principal_a.with_self_ty(tcx, source); - upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap(); - assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id())); - let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty( - tcx, trait_ref, - )) - }); - let iter = Some(existential_predicate) - .into_iter() - .chain( - data_a - .projection_bounds() - .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), - ) - .chain( - data_b - .auto_traits() - .map(ty::ExistentialPredicate::AutoTrait) - .map(ty::Binder::dummy), - ); - let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); - let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, repr_a); + let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty); + let unnormalized_upcast_principal = + util::supertraits(tcx, source_principal).nth(idx).unwrap(); - // Require that the traits involved in this upcast are **equal**; - // only the **lifetime bound** is changed. - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .sup(DefineOpaqueTypes::No, target, source_trait) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - obligation.predicate.rebind(outlives), - )); - } - _ => bug!(), - }; + let nested = self + .match_upcast_principal( + obligation, + unnormalized_upcast_principal, + a_data, + b_data, + a_region, + b_region, + )? + .expect("did not expect ambiguity during confirmation"); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -951,7 +910,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { vptr_offset += count_own_vtable_entries(tcx, trait_ref); - if trait_ref == upcast_trait_ref { + if trait_ref == unnormalized_upcast_principal { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -969,7 +928,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let vtable_vptr_slot = - prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap(); + prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap(); Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested)) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5da8d838db2..f1bd9f8b71a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2477,6 +2477,98 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Ok(Normalized { value: impl_args, obligations: nested_obligations }) } + fn match_upcast_principal( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + unnormalized_upcast_principal: ty::PolyTraitRef<'tcx>, + a_data: &'tcx ty::List>, + b_data: &'tcx ty::List>, + a_region: ty::Region<'tcx>, + b_region: ty::Region<'tcx>, + ) -> SelectionResult<'tcx, Vec>> { + let tcx = self.tcx(); + let mut nested = vec![]; + + let upcast_principal = normalize_with_depth_to( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + unnormalized_upcast_principal, + &mut nested, + ); + + for bound in b_data { + match bound.skip_binder() { + // Check that a_ty's supertrait (upcast_principal) is compatible + // with the target (b_ty). + ty::ExistentialPredicate::Trait(target_principal) => { + nested.extend( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup( + DefineOpaqueTypes::No, + upcast_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }), + bound.rebind(target_principal), + ) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(), + ); + } + // Check that b_ty's projection is satisfied by exactly one of + // a_ty's projections. First, we look through the list to see if + // any match. If not, error. Then, if *more* than one matches, we + // return ambiguity. Otherwise, if exactly one matches, equate + // it with b_ty's projection. + ty::ExistentialPredicate::Projection(target_projection) => { + let target_projection = bound.rebind(target_projection); + let mut matching_projections = + a_data.projection_bounds().filter(|source_projection| { + // Eager normalization means that we can just use can_eq + // here instead of equating and processing obligations. + source_projection.item_def_id() == target_projection.item_def_id() + && self.infcx.can_eq( + obligation.param_env, + *source_projection, + target_projection, + ) + }); + let Some(source_projection) = matching_projections.next() else { + return Err(SelectionError::Unimplemented); + }; + if matching_projections.next().is_some() { + return Ok(None); + } + nested.extend( + self.infcx + .at(&obligation.cause, obligation.param_env) + .sup(DefineOpaqueTypes::No, source_projection, target_projection) + .map_err(|_| SelectionError::Unimplemented)? + .into_obligations(), + ); + } + // Check that b_ty's auto traits are present in a_ty's bounds. + ty::ExistentialPredicate::AutoTrait(def_id) => { + if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + return Err(SelectionError::Unimplemented); + } + } + } + } + + nested.push(Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), + )); + + Ok(Some(nested)) + } + /// Normalize `where_clause_trait_ref` and try to match it against /// `obligation`. If successful, return any predicates that /// result from the normalization. diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 1a6a253f360..b0f8ea7a05d 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -216,6 +216,11 @@ bitflags! { /// Does this have `ConstKind::Placeholder`? const HAS_CT_PLACEHOLDER = 1 << 8; + /// Does this have placeholders? + const HAS_PLACEHOLDER = TypeFlags::HAS_TY_PLACEHOLDER.bits + | TypeFlags::HAS_RE_PLACEHOLDER.bits + | TypeFlags::HAS_CT_PLACEHOLDER.bits; + /// `true` if there are "names" of regions and so forth /// that are local to a particular fn/inferctxt const HAS_FREE_LOCAL_REGIONS = 1 << 9; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index bec0b11acd0..da60166b84d 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -2004,7 +2004,8 @@ impl Config { .unwrap(); if !(source_version == rustc_version || (source_version.major == rustc_version.major - && source_version.minor == rustc_version.minor + 1)) + && (source_version.minor == rustc_version.minor + || source_version.minor == rustc_version.minor + 1))) { let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1); eprintln!( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6f791aec3f2..12d620b5b18 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -136,19 +136,13 @@ pub(crate) fn new_handler( ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); Box::new( - EmitterWriter::stderr( - color_config, - source_map.map(|sm| sm as _), - None, - fallback_bundle, - short, - unstable_opts.teach, - diagnostic_width, - false, - unstable_opts.track_diagnostics, - TerminalUrl::No, - ) - .ui_testing(unstable_opts.ui_testing), + EmitterWriter::stderr(color_config, fallback_bundle) + .sm(source_map.map(|sm| sm as _)) + .short_message(short) + .teach(unstable_opts.teach) + .diagnostic_width(diagnostic_width) + .track_diagnostics(unstable_opts.track_diagnostics) + .ui_testing(unstable_opts.ui_testing), ) } ErrorOutputType::Json { pretty, json_rendered } => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a48273a5c73..3315ccad4d3 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError, TerminalUrl}; +use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID}; use rustc_interface::interface; @@ -558,33 +558,11 @@ pub(crate) fn make_test( rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false, ); - supports_color = EmitterWriter::stderr( - ColorConfig::Auto, - None, - None, - fallback_bundle.clone(), - false, - false, - Some(80), - false, - false, - TerminalUrl::No, - ) - .supports_color(); + supports_color = EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle.clone()) + .diagnostic_width(Some(80)) + .supports_color(); - let emitter = EmitterWriter::new( - Box::new(io::sink()), - None, - None, - fallback_bundle, - false, - false, - false, - None, - false, - false, - TerminalUrl::No, - ); + let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); @@ -760,19 +738,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { false, ); - let emitter = EmitterWriter::new( - Box::new(io::sink()), - None, - None, - fallback_bundle, - false, - false, - false, - None, - false, - false, - TerminalUrl::No, - ); + let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle); let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); let sess = ParseSess::with_span_handler(handler, sm); diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index b653f61d536..2b302988734 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -68,7 +68,7 @@ --test-arrow-color: #dedede; --test-arrow-background-color: rgba(78, 139, 202, 0.2); --test-arrow-hover-color: #dedede; - --test-arrow-hover-background-color: #4e8bca; + --test-arrow-hover-background-color: rgb(78, 139, 202); --target-background-color: #494a3d; --target-border-color: #bb7410; --kbd-color: #000; diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 6be25fc0544..56fd8cbef12 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -68,7 +68,7 @@ --test-arrow-color: #f5f5f5; --test-arrow-background-color: rgba(78, 139, 202, 0.2); --test-arrow-hover-color: #f5f5f5; - --test-arrow-hover-background-color: #4e8bca; + --test-arrow-hover-background-color: rgb(78, 139, 202); --target-background-color: #fdffd3; --target-border-color: #ad7c37; --kbd-color: #000; diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a5ec979ccd9..137bd9c9451 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -800,7 +800,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo && parent.span.ctxt() == e.span.ctxt() { match parent.kind { - ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _) + ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) if child.hir_id == e.hir_id => true, ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 00f70e586f4..2c4d93e33ba 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -16,7 +16,7 @@ use rustc_ast::token::CommentKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; -use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl}; +use rustc_errors::{Applicability, Handler, SuggestionStyle}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Expr}; @@ -718,16 +718,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) { rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = EmitterWriter::new( Box::new(io::sink()), - None, - None, fallback_bundle, - false, - false, - false, - None, - false, - false, - TerminalUrl::No, ); let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings(); let sess = ParseSess::with_span_handler(handler, sm); diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 83445c7a0ca..57df5683c9d 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -221,7 +221,7 @@ fn is_mutated_static(e: &hir::Expr<'_>) -> bool { match e.kind { Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), Path(_) => true, - Field(inner, _) | Index(inner, _) => is_mutated_static(inner), + Field(inner, _) | Index(inner, _, _) => is_mutated_static(inner), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 01a7c497cbe..f507f45d5bb 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { // Checking for slice indexing let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); - if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; + if let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind; if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); if let Ok(index_value) = index_value.try_into(); if index_value < max_suggested_slice; diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 22c14d9b04d..4f4f571773f 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { return; } - if let ExprKind::Index(array, index) = &expr.kind { + if let ExprKind::Index(array, index, _) = &expr.kind { let note = "the suggestion might not be applicable in constant blocks"; let ty = cx.typeck_results().expr_ty(array).peel_refs(); if let Some(range) = higher::Range::hir(index) { diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index 7d1f8ef29c8..d3fd0e8639e 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -60,8 +60,8 @@ pub(super) fn check<'tcx>( o.and_then(|(lhs, rhs)| { let rhs = fetch_cloned_expr(rhs); if_chain! { - if let ExprKind::Index(base_left, idx_left) = lhs.kind; - if let ExprKind::Index(base_right, idx_right) = rhs.kind; + if let ExprKind::Index(base_left, idx_left, _) = lhs.kind; + if let ExprKind::Index(base_right, idx_right, _) = rhs.kind; if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left)); if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some(); if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 2c20e9e8693..c4af46b8fd3 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -319,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // an index op - if let ExprKind::Index(seqexpr, idx) = expr.kind; + if let ExprKind::Index(seqexpr, idx, _) = expr.kind; if !self.check(idx, seqexpr, expr); then { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 7da9121fbb3..dd77c69ef88 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -162,7 +162,7 @@ fn never_loop_expr<'tcx>( ExprKind::Binary(_, e1, e2) | ExprKind::Assign(e1, e2, _) | ExprKind::AssignOp(_, e1, e2) - | ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id), + | ExprKind::Index(e1, e2, _) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id), ExprKind::Loop(b, _, _, _) => { // Break can come from the inner loop so remove them. absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id)) diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 8019f906aca..5153070cfe6 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -113,7 +113,7 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option { + ExprKind::Index(base, idx, _) if !idx.can_have_side_effects() => { can_move = false; fields.clear(); e = base; diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 2b9def1a688..201bb56efcd 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -204,7 +204,7 @@ fn find_stripping<'tcx>( if_chain! { if is_ref_str(self.cx, ex); let unref = peel_ref(ex); - if let ExprKind::Index(indexed, index) = &unref.kind; + if let ExprKind::Index(indexed, index, _) = &unref.kind; if let Some(higher::Range { start, end, .. }) = higher::Range::hir(index); if let ExprKind::Path(path) = &indexed.kind; if self.cx.qpath_res(path, ex.hir_id) == self.target; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs index 89dcac4d849..bd53ebd48c8 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs @@ -12,7 +12,7 @@ use super::MATCH_ON_VEC_ITEMS; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { if_chain! { if let Some(idx_expr) = is_vec_indexing(cx, scrutinee); - if let ExprKind::Index(vec, idx) = idx_expr.kind; + if let ExprKind::Index(vec, idx, _) = idx_expr.kind; then { // FIXME: could be improved to suggest surrounding every pattern with Some(_), @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) { fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::Index(array, index) = expr.kind; + if let ExprKind::Index(array, index, _) = expr.kind; if is_vector(cx, array); if !is_full_range(cx, index); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index ce7f9997b5a..ac7bc9bcca4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -12,7 +12,7 @@ use super::FILTER_NEXT; fn path_to_local(expr: &hir::Expr<'_>) -> Option { match expr.kind { hir::ExprKind::Field(f, _) => path_to_local(f), - hir::ExprKind::Index(recv, _) => path_to_local(recv), + hir::ExprKind::Index(recv, _, _) => path_to_local(recv), hir::ExprKind::Path(hir::QPath::Resolved( _, hir::Path { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs index e2029da8081..8f885e9f729 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() { // caller is a Slice if_chain! { - if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind; + if let hir::ExprKind::Index(caller_var, index_expr, _) = &caller_expr.kind; if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) = higher::Range::hir(index_expr); if let hir::ExprKind::Lit(start_lit) = &start_expr.kind; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index 57ec3a1f1e6..367cd6bd413 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -239,7 +239,7 @@ fn check_expr<'tcx>(vis: &mut ReadVisitor<'_, 'tcx>, expr: &'tcx Expr<'_>) -> St | ExprKind::MethodCall(..) | ExprKind::Call(_, _) | ExprKind::Assign(..) - | ExprKind::Index(_, _) + | ExprKind::Index(..) | ExprKind::Repeat(_, _) | ExprKind::Struct(_, _, _) => { walk_expr(vis, expr); diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index 46457400abc..f6b87b071b9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -119,7 +119,7 @@ fn condition_needs_parentheses(e: &Expr<'_>) -> bool { | ExprKind::Call(i, _) | ExprKind::Cast(i, _) | ExprKind::Type(i, _) - | ExprKind::Index(i, _) = inner.kind + | ExprKind::Index(i, _, _) = inner.kind { if matches!( i.kind, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index e6d3e72d1e6..5f2a324b05f 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -160,7 +160,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match peel_blocks(expr).kind { ExprKind::Lit(..) | ExprKind::Closure { .. } => true, ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)), - ExprKind::Index(a, b) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), + ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b), ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)), ExprKind::Repeat(inner, _) | ExprKind::Cast(inner, _) @@ -263,7 +263,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option Some(vec![a, b]), + ExprKind::Index(a, b, _) => Some(vec![a, b]), ExprKind::Binary(ref binop, a, b) if binop.node != BinOpKind::And && binop.node != BinOpKind::Or => { Some(vec![a, b]) }, diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index a70692d8ff8..243192385c2 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -438,7 +438,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { dereferenced_expr = parent_expr; }, - ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => { + ExprKind::Index(e, _, _) if ptr::eq(&**e, cur_expr) => { // `e[i]` => desugared to `*Index::index(&e, i)`, // meaning `e` must be referenced. // no need to go further up since a method call is involved now. diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 42299d8d42f..8009b00b4b9 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -695,7 +695,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: } }, // Indexing is fine for currently supported types. - ExprKind::Index(e, _) if e.hir_id == child_id => (), + ExprKind::Index(e, _, _) if e.hir_id == child_id => (), _ => set_skip_flag(), }, _ => set_skip_flag(), diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 8277ce724d4..4abfa0fc35c 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { if_chain! { if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind; if addressee.span.ctxt() == ctxt; - if let ExprKind::Index(indexed, range) = addressee.kind; + if let ExprKind::Index(indexed, range, _) = addressee.kind; if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull); then { let (expr_ty, expr_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(expr)); diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 4d45091f4b5..76f463fff7d 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -190,7 +190,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { ); } }, - ExprKind::Index(target, _idx) => { + ExprKind::Index(target, _idx, _) => { let e_ty = cx.typeck_results().expr_ty(target).peel_refs(); if e_ty.is_str() || is_type_lang_item(cx, e_ty, LangItem::String) { span_lint( @@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { // Find string::as_bytes if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind; - if let ExprKind::Index(left, right) = args.kind; + if let ExprKind::Index(left, right, _) = args.kind; let (method_names, expressions, _) = method_calls(left, 1); if method_names.len() == 1; if expressions.len() == 1; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index e2cdc48b583..23d6e2a845f 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -572,7 +572,7 @@ fn ident_difference_expr_with_base_location( | (AddrOf(_, _, _), AddrOf(_, _, _)) | (Path(_, _), Path(_, _)) | (Range(_, _, _), Range(_, _, _)) - | (Index(_, _), Index(_, _)) + | (Index(_, _, _), Index(_, _, _)) | (Field(_, _), Field(_, _)) | (AssignOp(_, _, _), AssignOp(_, _, _)) | (Assign(_, _, _), Assign(_, _, _)) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 98158ed0aee..548fabb8b73 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -86,8 +86,8 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa let mut applicability = Applicability::MachineApplicable; if !can_mut_borrow_both(cx, e1, e2) { - if let ExprKind::Index(lhs1, idx1) = e1.kind - && let ExprKind::Index(lhs2, idx2) = e2.kind + if let ExprKind::Index(lhs1, idx1, _) = e1.kind + && let ExprKind::Index(lhs2, idx2, _) = e2.kind && eq_expr_value(cx, lhs1, lhs2) && e1.span.ctxt() == ctxt && e2.span.ctxt() == ctxt diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs index 3766b8f8ed1..b6b653f6610 100644 --- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs +++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryAssignment { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Assign(target, ..) = &expr.kind { let mut base = target; - while let ExprKind::Field(f, _) | ExprKind::Index(f, _) = &base.kind { + while let ExprKind::Field(f, _) | ExprKind::Index(f, _, _) = &base.kind { base = f; } if is_temporary(base) && !is_adjusted(cx, base) { diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 7eec6982092..78ad52d8a87 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -103,11 +103,11 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & // Fix #11100 && tys.iter().all_equal() && let Some(locals) = (match first.kind { - ExprKind::Index(_, _) => elements + ExprKind::Index(..) => elements .iter() .enumerate() .map(|(i, i_expr)| -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Index(lhs, index) = i_expr.kind + if let ExprKind::Index(lhs, index, _) = i_expr.kind && let ExprKind::Lit(lit) = index.kind && let LitKind::Int(val, _) = lit.node { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 6b51974d739..f02c33cc674 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.ident(field_name); self.expr(object); }, - ExprKind::Index(object, index) => { + ExprKind::Index(object, index, _) => { bind!(self, object, index); kind!("Index({object}, {index})"); self.expr(object); diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 1d4fc24eb6c..3fa51216c77 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -88,7 +88,7 @@ impl VecPushSearcher { let mut last_place = parent; while let Some(parent) = get_parent_expr(cx, last_place) { if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..)) - || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id) + || matches!(parent.kind, ExprKind::Index(e, _, _) if e.hir_id == last_place.hir_id) { last_place = parent; } else { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 7e42924603a..2d0d6f559ad 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -178,7 +178,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r), (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re), (Continue(ll), Continue(rl)) => eq_label(ll, rl), - (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2), + (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => eq_expr(l1, r1) && eq_expr(l2, r2), (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv), (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp), (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm), diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 89f8a65c5ae..60fab1ec41a 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -163,7 +163,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ) => (Pat::Str("unsafe"), Pat::Str("}")), ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), - ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), + ExprKind::Index(e, _, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), ExprKind::Path(ref path) => qpath_search_pat(path), ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index f19e09a18ec..d38e3f1ae76 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -394,7 +394,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } }, - ExprKind::Index(arr, index) => self.index(arr, index), + ExprKind::Index(arr, index, _) => self.index(arr, index), ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), ExprKind::Field(local_expr, ref field) => { let result = self.expr(local_expr); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 3c969572b8e..0bcefba75a7 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -185,7 +185,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS .type_dependent_def_id(e.hir_id) .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true)); }, - ExprKind::Index(_, e) => { + ExprKind::Index(_, e, _) => { let ty = self.cx.typeck_results().expr_ty_adjusted(e); if is_copy(self.cx, ty) && !ty.is_ref() { self.eagerness |= NoChange; diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 85b3b005f93..fdc35cd4ddf 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -299,7 +299,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => { l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp) }, - (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), + (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => { self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r)) }, @@ -730,7 +730,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(e); self.hash_name(f.name); }, - ExprKind::Index(a, i) => { + ExprKind::Index(a, i, _) => { self.hash_expr(a); self.hash_expr(i); }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cf30930b76e..4cd8a8c3325 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -735,7 +735,7 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &' let mut result = vec![]; let root = loop { match e.kind { - ExprKind::Index(ep, _) | ExprKind::Field(ep, _) => { + ExprKind::Index(ep, _, _) | ExprKind::Field(ep, _) => { result.push(e); e = ep; }, @@ -782,7 +782,7 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) - return true; } }, - (ExprKind::Index(_, i1), ExprKind::Index(_, i2)) => { + (ExprKind::Index(_, i1, _), ExprKind::Index(_, i2, _)) => { if !eq_expr_value(cx, i1, i2) { return false; } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 5d7e1494fcf..a43a81bc63a 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -1011,6 +1011,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { }, // note: unable to trigger `Subslice` kind in tests ProjectionKind::Subslice => (), + // Doesn't have surface syntax. Only occurs in patterns. + ProjectionKind::OpaqueCast => (), ProjectionKind::Deref => { // Explicit derefs are typically handled later on, but // some items do not need explicit deref, such as array accesses, diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 45b5483e323..0669ea72eb3 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -31,7 +31,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty { let certainty = match &expr.kind { ExprKind::Unary(_, expr) | ExprKind::Field(expr, _) - | ExprKind::Index(expr, _) + | ExprKind::Index(expr, _, _) | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr), ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))), diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 09f447b27eb..f83988a6e32 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -329,7 +329,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, ExprKind::Unary(UnOp::Deref, e) if self.cx.typeck_results().expr_ty(e).is_ref() => (), ExprKind::Unary(_, e) if self.cx.typeck_results().expr_ty(e).peel_refs().is_primitive_ty() => (), - ExprKind::Index(base, _) + ExprKind::Index(base, _, _) if matches!( self.cx.typeck_results().expr_ty(base).peel_refs().kind(), ty::Slice(_) | ty::Array(..) @@ -629,7 +629,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, - ExprKind::Index(borrowed, consumed) + ExprKind::Index(borrowed, consumed, _) | ExprKind::Assign(borrowed, consumed, _) | ExprKind::AssignOp(_, borrowed, consumed) => { helper(typeck, false, borrowed, f)?; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 07a54cb26d3..c1987420417 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2466,8 +2466,13 @@ impl<'test> TestCx<'test> { rustc.args(&["-A", "unused"]); } - // Allow tests to use internal features. - rustc.args(&["-A", "internal_features"]); + // #[cfg(not(bootstrap)] unconditionally pass flag after beta bump + // since `ui-fulldeps --stage=1` builds using the stage 0 compiler, + // which doesn't have this lint. + if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") { + // Allow tests to use internal features. + rustc.args(&["-A", "internal_features"]); + } if self.props.force_host { self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags); diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index f195bd5ac8a..716b690daaa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -a7caaae9fbef81325887aea060fc551da4589c6f \ No newline at end of file +fca59ab5f0e7df7d816bed77a32abc0045ebe80b \ No newline at end of file diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index e929091b396..ea7cba3f346 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -13,11 +13,7 @@ use log::trace; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; -use rustc_middle::ty::{ - self, - layout::{HasParamEnv, LayoutOf}, - Ty, -}; +use rustc_middle::ty::{self, layout::HasParamEnv, Ty}; use rustc_target::abi::{Abi, Align, Size}; use crate::borrow_tracker::{ @@ -993,8 +989,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the usual retagging logic. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?; - let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout); + let ptr = this.mplace_to_ref(place)?; // Reborrow it. With protection! That is the entire point. let new_perm = NewPermission::Uniform { perm: Permission::Unique, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 51006ee97c9..283bc94d3cf 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -5,11 +5,7 @@ use rustc_target::abi::{Abi, Align, Size}; use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields}; use rustc_middle::{ mir::{Mutability, RetagKind}, - ty::{ - self, - layout::{HasParamEnv, LayoutOf}, - Ty, - }, + ty::{self, layout::HasParamEnv, Ty}, }; use rustc_span::def_id::DefId; @@ -493,8 +489,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // We have to turn the place into a pointer to use the usual retagging logic. // (The pointer type does not matter, so we use a raw pointer.) - let ptr_layout = this.layout_of(Ty::new_mut_ptr(this.tcx.tcx, place.layout.ty))?; - let ptr = ImmTy::from_immediate(place.to_ref(this), ptr_layout); + let ptr = this.mplace_to_ref(place)?; // Reborrow it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_active(), diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 739afb4e0ac..c3c07f310bf 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -256,7 +256,7 @@ pub(crate) fn format_expr( shape, SeparatorPlace::Back, ), - ast::ExprKind::Index(ref expr, ref index) => { + ast::ExprKind::Index(ref expr, ref index, _) => { rewrite_index(&**expr, &**index, context, shape) } ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair( @@ -1342,7 +1342,7 @@ pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool { | ast::ExprKind::Field(ref expr, _) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr), - ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs), + ast::ExprKind::Index(ref lhs, ref rhs, _) => is_simple_expr(lhs) && is_simple_expr(rhs), ast::ExprKind::Repeat(ref lhs, ref rhs) => { is_simple_expr(lhs) && is_simple_expr(&*rhs.value) } diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs index aac5e59b860..4c37116f120 100644 --- a/src/tools/rustfmt/src/matches.rs +++ b/src/tools/rustfmt/src/matches.rs @@ -594,7 +594,7 @@ fn can_flatten_block_around_this(body: &ast::Expr) -> bool { ast::ExprKind::AddrOf(_, _, ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) - | ast::ExprKind::Index(ref expr, _) + | ast::ExprKind::Index(ref expr, _, _) | ast::ExprKind::Cast(ref expr, _) => can_flatten_block_around_this(expr), _ => false, } diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index aa75b477473..945e3e42fdd 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::{Lrc, Send}; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::translation::Translate; -use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel, TerminalUrl}; +use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; use rustc_span::{ source_map::{FilePathMapping, SourceMap}, @@ -139,18 +139,7 @@ fn default_handler( rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false, ); - Box::new(EmitterWriter::stderr( - emit_color, - Some(source_map.clone()), - None, - fallback_bundle, - false, - false, - None, - false, - false, - TerminalUrl::No, - )) + Box::new(EmitterWriter::stderr(emit_color, fallback_bundle).sm(Some(source_map.clone()))) }; Handler::with_emitter(Box::new(SilentOnIgnoredFilesEmitter { has_non_ignorable_parser_errors: false, diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 890a05b8c82..4fc5a9b6896 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -441,7 +441,7 @@ pub(crate) fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr { | ast::ExprKind::Assign(ref e, _, _) | ast::ExprKind::AssignOp(_, ref e, _) | ast::ExprKind::Field(ref e, _) - | ast::ExprKind::Index(ref e, _) + | ast::ExprKind::Index(ref e, _, _) | ast::ExprKind::Range(Some(ref e), _, _) | ast::ExprKind::Try(ref e) => left_most_sub_expr(e), _ => e, @@ -479,7 +479,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Match(..) => repr.contains('\n'), ast::ExprKind::Paren(ref expr) | ast::ExprKind::Binary(_, _, ref expr) - | ast::ExprKind::Index(_, ref expr) + | ast::ExprKind::Index(_, ref expr, _) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr), diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a015c36d7eb..22e9b46347a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -138,8 +138,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "crossbeam-utils", "crypto-common", "cstr", + "darling", + "darling_core", + "darling_macro", "datafrog", "derive_more", + "derive_setters", "digest", "displaydoc", "dissimilar", @@ -158,6 +162,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "fluent-bundle", "fluent-langneg", "fluent-syntax", + "fnv", "fortanix-sgx-abi", "generic-array", "getopts", @@ -171,6 +176,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "icu_provider", "icu_provider_adapters", "icu_provider_macros", + "ident_case", "indexmap", "instant", "intl-memoizer", @@ -245,6 +251,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "stable_deref_trait", "stacker", "static_assertions", + "strsim", "syn", "synstructure", "tempfile", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 44c7c07d3a0..930b7408390 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1893; -const ROOT_ENTRY_LIMIT: usize = 873; +const ROOT_ENTRY_LIMIT: usize = 866; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/rustdoc-gui/run-on-hover.goml b/tests/rustdoc-gui/run-on-hover.goml index b5fc49eacac..1f87febcec6 100644 --- a/tests/rustdoc-gui/run-on-hover.goml +++ b/tests/rustdoc-gui/run-on-hover.goml @@ -33,22 +33,22 @@ define-function: ( call-function: ("check-run-button", { "theme": "ayu", - "color": "rgb(120, 135, 151)", + "color": "#788797", "background": "rgba(57, 175, 215, 0.09)", - "hover_color": "rgb(197, 197, 197)", + "hover_color": "#c5c5c5", "hover_background": "rgba(57, 175, 215, 0.37)", }) call-function: ("check-run-button", { "theme": "dark", - "color": "rgb(222, 222, 222)", + "color": "#dedede", "background": "rgba(78, 139, 202, 0.2)", - "hover_color": "rgb(222, 222, 222)", + "hover_color": "#dedede", "hover_background": "rgb(78, 139, 202)", }) call-function: ("check-run-button", { "theme": "light", - "color": "rgb(245, 245, 245)", + "color": "#f5f5f5", "background": "rgba(78, 139, 202, 0.2)", - "hover_color": "rgb(245, 245, 245)", + "hover_color": "#f5f5f5", "hover_background": "rgb(78, 139, 202)", }) diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs index 2e9b13d0cac..8e39f471824 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs @@ -5,14 +5,15 @@ // @set Carrier = '$.index[*][?(@.name=="Carrier")].id' pub struct Carrier<'a>(&'a ()); -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.generic_params[*].name' \""'b"\" -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"' -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.trait' null -// @is '$.index[*][?(@.name=="User")].inner.typedef.type.function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' - -pub type User = for<'b> fn(Carrier<'b>::Focus); +// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"' +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\" +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"' +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null +// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' +pub fn user(_: for<'b> fn(Carrier<'b>::Focus)) {} impl<'a> Carrier<'a> { pub type Focus = &'a mut T; diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs index 942e323efca..d12e5f4a784 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs @@ -5,11 +5,13 @@ // @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' pub struct Parametrized(T); -// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.id' $Parametrized -// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" -// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.name' '"Proj"' -// @is '$.index[*][?(@.name=="Test")].inner.typedef.type.qualified_path.trait' null -pub type Test = Parametrized::Proj; +// @count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1 +// @is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"' +// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized +// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" +// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"' +// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null +pub fn test(_: Parametrized::Proj) {} /// param_bool impl Parametrized { diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc/inherent-projections.rs index 9bda0acaf83..25f51282617 100644 --- a/tests/rustdoc/inherent-projections.rs +++ b/tests/rustdoc/inherent-projections.rs @@ -13,8 +13,8 @@ impl Owner { } // Make sure we handle bound vars correctly. -// @has 'inherent_projections/type.User.html' '//pre[@class="rust item-decl"]' "for<'a> fn(_: Carrier<'a>::Focus)" -pub type User = for<'a> fn(Carrier<'a>::Focus); +// @has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))" +pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {} pub struct Carrier<'a>(&'a ()); @@ -27,11 +27,11 @@ impl<'a> Carrier<'a> { // FIXME(inherent_associated_types): Below we link to `Proj` but we should link to `Proj-1`. // The current test checks for the buggy behavior for demonstration purposes. -// @has 'inherent_projections/type.Test.html' -// @has - '//pre[@class="rust item-decl"]' "Parametrized" +// @has 'inherent_projections/fn.test.html' +// @has - '//pre[@class="rust item-decl"]' "test(_: Parametrized::Proj)" // @has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj' // @!has - '//pre[@class="rust item-decl"]//a[@class="associatedtype"]/@href' 'struct.Parametrized.html#associatedtype.Proj-1' -pub type Test = Parametrized::Proj; +pub fn test(_: Parametrized::Proj) {} pub struct Parametrized(T); diff --git a/tests/ui/array-slice-vec/slice-2.stderr b/tests/ui/array-slice-vec/slice-2.stderr index 561feb90f0a..b122b46914c 100644 --- a/tests/ui/array-slice-vec/slice-2.stderr +++ b/tests/ui/array-slice-vec/slice-2.stderr @@ -1,26 +1,26 @@ error[E0608]: cannot index into a value of type `Foo` - --> $DIR/slice-2.rs:7:6 + --> $DIR/slice-2.rs:7:7 | LL | &x[..]; - | ^^^^^ + | ^^^^ error[E0608]: cannot index into a value of type `Foo` - --> $DIR/slice-2.rs:8:6 + --> $DIR/slice-2.rs:8:7 | LL | &x[Foo..]; - | ^^^^^^^^ + | ^^^^^^^ error[E0608]: cannot index into a value of type `Foo` - --> $DIR/slice-2.rs:9:6 + --> $DIR/slice-2.rs:9:7 | LL | &x[..Foo]; - | ^^^^^^^^ + | ^^^^^^^ error[E0608]: cannot index into a value of type `Foo` - --> $DIR/slice-2.rs:10:6 + --> $DIR/slice-2.rs:10:7 | LL | &x[Foo..Foo]; - | ^^^^^^^^^^^ + | ^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/associated-inherent-types/issue-111879-0.rs b/tests/ui/associated-inherent-types/issue-111879-0.rs index e37f7d34ab5..d01354465df 100644 --- a/tests/ui/associated-inherent-types/issue-111879-0.rs +++ b/tests/ui/associated-inherent-types/issue-111879-0.rs @@ -5,10 +5,8 @@ pub struct Carrier<'a>(&'a ()); -pub type User = for<'b> fn(Carrier<'b>::Focus); - impl<'a> Carrier<'a> { - pub type Focus = &'a mut User; //~ ERROR overflow evaluating associated type + pub type Focus = &'a mut for<'b> fn(Carrier<'b>::Focus); //~ ERROR overflow evaluating associated type } fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111879-0.stderr b/tests/ui/associated-inherent-types/issue-111879-0.stderr index 7bdbad44017..f6367c88aea 100644 --- a/tests/ui/associated-inherent-types/issue-111879-0.stderr +++ b/tests/ui/associated-inherent-types/issue-111879-0.stderr @@ -1,8 +1,8 @@ error: overflow evaluating associated type `Carrier<'b>::Focus` - --> $DIR/issue-111879-0.rs:11:25 + --> $DIR/issue-111879-0.rs:9:25 | -LL | pub type Focus = &'a mut User; - | ^^^^^^^^^^^^ +LL | pub type Focus = &'a mut for<'b> fn(Carrier<'b>::Focus); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/associated-inherent-types/late-bound-regions.rs b/tests/ui/associated-inherent-types/late-bound-regions.rs index 488a2cda649..1dbeb00d495 100644 --- a/tests/ui/associated-inherent-types/late-bound-regions.rs +++ b/tests/ui/associated-inherent-types/late-bound-regions.rs @@ -3,8 +3,6 @@ // Test if we correctly normalize `S<'a>::P` with respect to late-bound regions. -type Function = for<'a> fn(&'a i32) -> S<'a>::P; - struct S<'a>(&'a ()); trait Inter { @@ -16,7 +14,7 @@ impl<'a> S<'a> { } fn ret_ref_local<'e>() -> &'e i32 { - let f: Function = |x| x; + let f: for<'a> fn(&'a i32) -> S<'a>::P = |x| x; let local = 0; f(&local) //~ ERROR cannot return value referencing local variable `local` diff --git a/tests/ui/associated-inherent-types/late-bound-regions.stderr b/tests/ui/associated-inherent-types/late-bound-regions.stderr index 4706fcca91d..0dd17b05cd0 100644 --- a/tests/ui/associated-inherent-types/late-bound-regions.stderr +++ b/tests/ui/associated-inherent-types/late-bound-regions.stderr @@ -1,5 +1,5 @@ error[E0515]: cannot return value referencing local variable `local` - --> $DIR/late-bound-regions.rs:22:5 + --> $DIR/late-bound-regions.rs:20:5 | LL | f(&local) | ^^------^ diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr deleted file mode 100644 index 4396435a6dd..00000000000 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs.alias.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0220]: associated type `Proj` not found for `Family>` in the current scope - --> $DIR/not-found-self-type-differs.rs:17:34 - | -LL | struct Family(T); - | ---------------- associated item `Proj` not found for this struct -... -LL | type Alias = Family>::Proj; - | ^^^^ associated item not found in `Family>` - | - = note: the associated type was found for - - `Family<()>` - - `Family>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr deleted file mode 100644 index d527db02217..00000000000 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs.local.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error[E0220]: associated type `Proj` not found for `Family` in the current scope - --> $DIR/not-found-self-type-differs.rs:21:40 - | -LL | struct Family(T); - | ---------------- associated item `Proj` not found for this struct -... -LL | let _: Family::Proj = (); - | ^^^^ associated item not found in `Family` - | - = note: the associated type was found for - - `Family<()>` - - `Family>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs index 93f58dcb6e6..76c5d4e7f69 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs.rs +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.rs @@ -1,5 +1,3 @@ -// revisions: local alias - #![feature(inherent_associated_types)] #![allow(incomplete_features)] @@ -13,10 +11,7 @@ impl Family> { type Proj = Self; } -#[cfg(alias)] -type Alias = Family>::Proj; //[alias]~ ERROR associated type `Proj` not found for `Family>` - fn main() { - #[cfg(local)] - let _: Family::Proj = (); //[local]~ ERROR associated type `Proj` not found for `Family` + let _: Family>::Proj; //~ ERROR associated type `Proj` not found for `Family>` + let _: Family::Proj = (); //~ ERROR associated type `Proj` not found for `Family` } diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr new file mode 100644 index 00000000000..1871407c64f --- /dev/null +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs.stderr @@ -0,0 +1,29 @@ +error[E0220]: associated type `Proj` not found for `Family>` in the current scope + --> $DIR/not-found-self-type-differs.rs:15:32 + | +LL | struct Family(T); + | ---------------- associated item `Proj` not found for this struct +... +LL | let _: Family>::Proj; + | ^^^^ associated item not found in `Family>` + | + = note: the associated type was found for + - `Family<()>` + - `Family>` + +error[E0220]: associated type `Proj` not found for `Family` in the current scope + --> $DIR/not-found-self-type-differs.rs:16:40 + | +LL | struct Family(T); + | ---------------- associated item `Proj` not found for this struct +... +LL | let _: Family::Proj = (); + | ^^^^ associated item not found in `Family` + | + = note: the associated type was found for + - `Family<()>` + - `Family>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/substitute-params-bad.rs b/tests/ui/associated-inherent-types/substitute-params-bad.rs index 00eb1a14da4..a5d73c7b49f 100644 --- a/tests/ui/associated-inherent-types/substitute-params-bad.rs +++ b/tests/ui/associated-inherent-types/substitute-params-bad.rs @@ -17,7 +17,7 @@ impl Subj<(T, S)> { } fn main() { - type A = S<()>::P; + let _: S<()>::P; let _: Subj<(i32, i32)>::Un = 0i32; //~ ERROR mismatched types } diff --git a/tests/ui/associated-inherent-types/substitute-params.rs b/tests/ui/associated-inherent-types/substitute-params.rs index e94d6833159..631340b2b4d 100644 --- a/tests/ui/associated-inherent-types/substitute-params.rs +++ b/tests/ui/associated-inherent-types/substitute-params.rs @@ -15,8 +15,7 @@ impl S<(T,)> { fn main() { // Regression test for issue #104240. - type A = S<()>::P; - let _: A = (); + let _: S<()>::P = (); // Regression test for issue #107468. let _: S<(i32,)>::Un = 0i32; diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs index b32b4288ac9..5c59f217be6 100644 --- a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs +++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.rs @@ -1,4 +1,5 @@ -// check-pass +// FIXME(inherent_associated_types): This should be `check-pass` +// known-bug: #108491 // compile-flags: --crate-type=lib #![feature(inherent_associated_types)] @@ -17,7 +18,6 @@ pub type Alias = (Source::Assoc,); - pub struct Source(T); pub trait Bound {} diff --git a/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr new file mode 100644 index 00000000000..5e18543fc90 --- /dev/null +++ b/tests/ui/associated-inherent-types/type-alias-bounds-are-enforced.stderr @@ -0,0 +1,55 @@ +error[E0391]: cycle detected when expanding type alias `Alias` + --> $DIR/type-alias-bounds-are-enforced.rs:19:1 + | +LL | pub type Alias = (Source::Assoc,); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing the variances of `Source`... + --> $DIR/type-alias-bounds-are-enforced.rs:21:1 + | +LL | pub struct Source(T); + | ^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing the variances for items in this crate... + = note: ...which again requires expanding type alias `Alias`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/type-alias-bounds-are-enforced.rs:5:1 + | +LL | / #![feature(inherent_associated_types)] +LL | | #![allow(incomplete_features)] +LL | | +LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*). +... | +LL | | pub type Assoc = (); +LL | | } + | |_^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when expanding type alias `Alias` + --> $DIR/type-alias-bounds-are-enforced.rs:19:1 + | +LL | pub type Alias = (Source::Assoc,); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires computing the variances of `Source`... + --> $DIR/type-alias-bounds-are-enforced.rs:21:1 + | +LL | pub struct Source(T); + | ^^^^^^^^^^^^^^^^^^^^ + = note: ...which requires computing the variances for items in this crate... + = note: ...which again requires expanding type alias `Alias`, completing the cycle +note: cycle used when collecting item types in top-level module + --> $DIR/type-alias-bounds-are-enforced.rs:5:1 + | +LL | / #![feature(inherent_associated_types)] +LL | | #![allow(incomplete_features)] +LL | | +LL | | // Bounds on the self type play a major role in the resolution of inherent associated types (*). +... | +LL | | pub type Assoc = (); +LL | | } + | |_^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/async-await/track-caller/async-block.afn.stderr b/tests/ui/async-await/track-caller/async-block.afn.stderr new file mode 100644 index 00000000000..2302722eecc --- /dev/null +++ b/tests/ui/async-await/track-caller/async-block.afn.stderr @@ -0,0 +1,30 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:8:13 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:15:13 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:23:17 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-block.nofeat.stderr b/tests/ui/async-await/track-caller/async-block.nofeat.stderr new file mode 100644 index 00000000000..2302722eecc --- /dev/null +++ b/tests/ui/async-await/track-caller/async-block.nofeat.stderr @@ -0,0 +1,30 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:8:13 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:15:13 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-block.rs:23:17 + | +LL | let _ = #[track_caller] async { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-block.rs b/tests/ui/async-await/track-caller/async-block.rs index 8ddd4ab1186..24711b966b5 100644 --- a/tests/ui/async-await/track-caller/async-block.rs +++ b/tests/ui/async-await/track-caller/async-block.rs @@ -1,9 +1,27 @@ // edition:2021 +// revisions: afn nofeat #![feature(stmt_expr_attributes)] +#![cfg_attr(afn, feature(async_fn_track_caller))] fn main() { let _ = #[track_caller] async { //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] }; } + +#[track_caller] +async fn foo() { + let _ = #[track_caller] async { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; +} + +#[track_caller] +async fn foo2() { + let _ = async { + let _ = #[track_caller] async { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; + }; +} diff --git a/tests/ui/async-await/track-caller/async-block.stderr b/tests/ui/async-await/track-caller/async-block.stderr deleted file mode 100644 index 21d1054d220..00000000000 --- a/tests/ui/async-await/track-caller/async-block.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-block.rs:6:13 - | -LL | let _ = #[track_caller] async { - | ^^^^^^^^^^^^^^^ - | - = note: see issue #87417 for more information - = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr new file mode 100644 index 00000000000..739c04a7673 --- /dev/null +++ b/tests/ui/async-await/track-caller/async-closure-gate.afn.stderr @@ -0,0 +1,57 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:8:13 + | +LL | let _ = #[track_caller] async || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:15:13 + | +LL | let _ = #[track_caller] async || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:21:13 + | +LL | let _ = #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:28:17 + | +LL | let _ = #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:36:9 + | +LL | #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:45:13 + | +LL | #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr new file mode 100644 index 00000000000..739c04a7673 --- /dev/null +++ b/tests/ui/async-await/track-caller/async-closure-gate.nofeat.stderr @@ -0,0 +1,57 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:8:13 + | +LL | let _ = #[track_caller] async || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:15:13 + | +LL | let _ = #[track_caller] async || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:21:13 + | +LL | let _ = #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:28:17 + | +LL | let _ = #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:36:9 + | +LL | #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/async-closure-gate.rs:45:13 + | +LL | #[track_caller] || { + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/async-closure-gate.rs b/tests/ui/async-await/track-caller/async-closure-gate.rs index d9d55685599..8d8d081aa90 100644 --- a/tests/ui/async-await/track-caller/async-closure-gate.rs +++ b/tests/ui/async-await/track-caller/async-closure-gate.rs @@ -1,9 +1,50 @@ // edition:2021 +// revisions: afn nofeat #![feature(async_closure, stmt_expr_attributes)] +#![cfg_attr(afn, feature(async_fn_track_caller))] fn main() { let _ = #[track_caller] async || { //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] }; } + +#[track_caller] +async fn foo() { + let _ = #[track_caller] async || { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; +} + +async fn foo2() { + let _ = #[track_caller] || { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; +} + +fn foo3() { + async { + let _ = #[track_caller] || { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; + } +} + +async fn foo4() { + let _ = || { + #[track_caller] || { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; + }; +} + +fn foo5() { + async { + let _ = || { + #[track_caller] || { + //~^ ERROR `#[track_caller]` on closures is currently unstable [E0658] + }; + }; + } +} diff --git a/tests/ui/async-await/track-caller/async-closure-gate.stderr b/tests/ui/async-await/track-caller/async-closure-gate.stderr deleted file mode 100644 index 498f1b43b9b..00000000000 --- a/tests/ui/async-await/track-caller/async-closure-gate.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[track_caller]` on closures is currently unstable - --> $DIR/async-closure-gate.rs:6:13 - | -LL | let _ = #[track_caller] async || { - | ^^^^^^^^^^^^^^^ - | - = note: see issue #87417 for more information - = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr new file mode 100644 index 00000000000..f3090e3b9a6 --- /dev/null +++ b/tests/ui/async-await/track-caller/panic-track-caller.cls.stderr @@ -0,0 +1,31 @@ +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:53:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +... +LL | / async fn bar_track_caller() { +LL | | panic!() +LL | | } + | |_- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + = note: `#[warn(ungated_async_fn_track_caller)]` on by default + +warning: `#[track_caller]` on async functions is a no-op + --> $DIR/panic-track-caller.rs:67:5 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +... +LL | / async fn bar_assoc() { +LL | | panic!(); +LL | | } + | |_____- this function will not propagate the caller location + | + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable + +warning: 2 warnings emitted + diff --git a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr index 51ea225f4cb..f3090e3b9a6 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr +++ b/tests/ui/async-await/track-caller/panic-track-caller.nofeat.stderr @@ -1,29 +1,31 @@ warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:50:1 + --> $DIR/panic-track-caller.rs:53:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ +... LL | / async fn bar_track_caller() { LL | | panic!() LL | | } | |_- this function will not propagate the caller location | - = note: see issue #87417 for more information - = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable = note: `#[warn(ungated_async_fn_track_caller)]` on by default warning: `#[track_caller]` on async functions is a no-op - --> $DIR/panic-track-caller.rs:62:5 + --> $DIR/panic-track-caller.rs:67:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ +... LL | / async fn bar_assoc() { LL | | panic!(); LL | | } | |_____- this function will not propagate the caller location | - = note: see issue #87417 for more information - = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + = note: see issue #110011 for more information + = help: add `#![feature(async_fn_track_caller)]` to the crate attributes to enable warning: 2 warnings emitted diff --git a/tests/ui/async-await/track-caller/panic-track-caller.rs b/tests/ui/async-await/track-caller/panic-track-caller.rs index 65bb23e0b4b..df8290e5fff 100644 --- a/tests/ui/async-await/track-caller/panic-track-caller.rs +++ b/tests/ui/async-await/track-caller/panic-track-caller.rs @@ -1,9 +1,12 @@ // run-pass // edition:2021 -// revisions: feat nofeat +// revisions: afn cls nofeat // needs-unwind +// gate-test-async_fn_track_caller #![feature(async_closure, stmt_expr_attributes)] -#![cfg_attr(feat, feature(closure_track_caller))] +#![cfg_attr(afn, feature(async_fn_track_caller))] +#![cfg_attr(cls, feature(closure_track_caller))] +#![allow(unused)] use std::future::Future; use std::panic; @@ -47,7 +50,9 @@ async fn foo() { bar().await } -#[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op +#[track_caller] +//[cls]~^ WARN `#[track_caller]` on async functions is a no-op +//[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op async fn bar_track_caller() { panic!() } @@ -59,7 +64,9 @@ async fn foo_track_caller() { struct Foo; impl Foo { - #[track_caller] //[nofeat]~ WARN `#[track_caller]` on async functions is a no-op + #[track_caller] + //[cls]~^ WARN `#[track_caller]` on async functions is a no-op + //[nofeat]~^^ WARN `#[track_caller]` on async functions is a no-op async fn bar_assoc() { panic!(); } @@ -71,7 +78,7 @@ async fn foo_assoc() { // Since compilation is expected to fail for this fn when using // `nofeat`, we test that separately in `async-closure-gate.rs` -#[cfg(feat)] +#[cfg(cls)] async fn foo_closure() { let c = #[track_caller] async || { panic!(); @@ -81,7 +88,7 @@ async fn foo_closure() { // Since compilation is expected to fail for this fn when using // `nofeat`, we test that separately in `async-block.rs` -#[cfg(feat)] +#[cfg(cls)] async fn foo_block() { let a = #[track_caller] async { panic!(); @@ -106,21 +113,22 @@ fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 { } fn main() { - assert_eq!(panicked_at(|| block_on(foo())), 43); + assert_eq!(panicked_at(|| block_on(foo())), 46 +); - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 56); - #[cfg(nofeat)] - assert_eq!(panicked_at(|| block_on(foo_track_caller())), 52); + #[cfg(afn)] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 61); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| block_on(foo_track_caller())), 57); - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 69); - #[cfg(nofeat)] - assert_eq!(panicked_at(|| block_on(foo_assoc())), 64); + #[cfg(afn)] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 76); + #[cfg(any(cls, nofeat))] + assert_eq!(panicked_at(|| block_on(foo_assoc())), 71); - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_closure())), 79); + #[cfg(cls)] + assert_eq!(panicked_at(|| block_on(foo_closure())), 84); - #[cfg(feat)] - assert_eq!(panicked_at(|| block_on(foo_block())), 89); + #[cfg(cls)] + assert_eq!(panicked_at(|| block_on(foo_block())), 96); } diff --git a/tests/ui/borrowck/suggest-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-local-var-for-vector.stderr index ea92d76b4ec..c8d00f7b222 100644 --- a/tests/ui/borrowck/suggest-local-var-for-vector.stderr +++ b/tests/ui/borrowck/suggest-local-var-for-vector.stderr @@ -3,10 +3,10 @@ error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mu | LL | vec[vec.len() - 1] = 123; | ----^^^----------- - | | | - | | immutable borrow occurs here + | | || + | | |immutable borrow occurs here + | | mutable borrow later used here | mutable borrow occurs here - | mutable borrow later used here | help: try adding a local storing this... --> $DIR/suggest-local-var-for-vector.rs:3:9 @@ -14,10 +14,10 @@ help: try adding a local storing this... LL | vec[vec.len() - 1] = 123; | ^^^^^^^^^ help: ...and then using that local here - --> $DIR/suggest-local-var-for-vector.rs:3:5 + --> $DIR/suggest-local-var-for-vector.rs:3:8 | LL | vec[vec.len() - 1] = 123; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr index 6007beb7753..368d728101c 100644 --- a/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr +++ b/tests/ui/borrowck/suggest-storing-local-var-for-vector.stderr @@ -3,10 +3,10 @@ error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mu | LL | vec[vec.len() - 1] = 123; | ----^^^----------- - | | | - | | immutable borrow occurs here + | | || + | | |immutable borrow occurs here + | | mutable borrow later used here | mutable borrow occurs here - | mutable borrow later used here | help: try adding a local storing this... --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 @@ -14,10 +14,10 @@ help: try adding a local storing this... LL | vec[vec.len() - 1] = 123; | ^^^^^^^^^ help: ...and then using that local here - --> $DIR/suggest-storing-local-var-for-vector.rs:3:5 + --> $DIR/suggest-storing-local-var-for-vector.rs:3:8 | LL | vec[vec.len() - 1] = 123; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr index efd63a08aae..e122977b9f2 100644 --- a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr +++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr @@ -50,42 +50,42 @@ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as muta | LL | i[i[3]] = 4; | --^---- - | | | - | | immutable borrow occurs here + | ||| + | ||immutable borrow occurs here + | |mutable borrow later used here | mutable borrow occurs here - | mutable borrow later used here | help: try adding a local storing this... - --> $DIR/two-phase-nonrecv-autoref.rs:132:7 + --> $DIR/two-phase-nonrecv-autoref.rs:132:8 | LL | i[i[3]] = 4; - | ^^^^ + | ^^^ help: ...and then using that local here - --> $DIR/two-phase-nonrecv-autoref.rs:132:5 + --> $DIR/two-phase-nonrecv-autoref.rs:132:6 | LL | i[i[3]] = 4; - | ^^^^^^^ + | ^^^^^^ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable --> $DIR/two-phase-nonrecv-autoref.rs:138:7 | LL | i[i[3]] = i[4]; | --^---- - | | | - | | immutable borrow occurs here + | ||| + | ||immutable borrow occurs here + | |mutable borrow later used here | mutable borrow occurs here - | mutable borrow later used here | help: try adding a local storing this... - --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + --> $DIR/two-phase-nonrecv-autoref.rs:138:8 | LL | i[i[3]] = i[4]; - | ^^^^ + | ^^^ help: ...and then using that local here - --> $DIR/two-phase-nonrecv-autoref.rs:138:5 + --> $DIR/two-phase-nonrecv-autoref.rs:138:6 | LL | i[i[3]] = i[4]; - | ^^^^^^^ + | ^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/consts/issue-94675.stderr b/tests/ui/consts/issue-94675.stderr index cee4dfda2c9..f51f305ac38 100644 --- a/tests/ui/consts/issue-94675.stderr +++ b/tests/ui/consts/issue-94675.stderr @@ -7,10 +7,10 @@ LL | self.bar[0] = baz.len(); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const operator in constant functions - --> $DIR/issue-94675.rs:11:9 + --> $DIR/issue-94675.rs:11:17 | LL | self.bar[0] = baz.len(); - | ^^^^^^^^^^^ + | ^^^ | note: impl defined here, but it is not `const` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/tests/ui/dst/issue-113447.fixed b/tests/ui/dst/issue-113447.fixed new file mode 100644 index 00000000000..536f680f697 --- /dev/null +++ b/tests/ui/dst/issue-113447.fixed @@ -0,0 +1,25 @@ +// run-rustfix + +pub struct Bytes; + +impl Bytes { + pub fn as_slice(&self) -> &[u8] { + todo!() + } +} + +impl PartialEq<[u8]> for Bytes { + fn eq(&self, other: &[u8]) -> bool { + self.as_slice() == other + } +} + +impl PartialEq for &[u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == **self + } +} + +fn main() { + let _ = &[0u8] == &[0xAA][..]; //~ ERROR can't compare `&[u8; 1]` with `[{integer}; 1]` +} diff --git a/tests/ui/dst/issue-113447.rs b/tests/ui/dst/issue-113447.rs new file mode 100644 index 00000000000..c10a4f2ff8e --- /dev/null +++ b/tests/ui/dst/issue-113447.rs @@ -0,0 +1,25 @@ +// run-rustfix + +pub struct Bytes; + +impl Bytes { + pub fn as_slice(&self) -> &[u8] { + todo!() + } +} + +impl PartialEq<[u8]> for Bytes { + fn eq(&self, other: &[u8]) -> bool { + self.as_slice() == other + } +} + +impl PartialEq for &[u8] { + fn eq(&self, other: &Bytes) -> bool { + *other == **self + } +} + +fn main() { + let _ = &[0u8] == [0xAA]; //~ ERROR can't compare `&[u8; 1]` with `[{integer}; 1]` +} diff --git a/tests/ui/dst/issue-113447.stderr b/tests/ui/dst/issue-113447.stderr new file mode 100644 index 00000000000..240553a675b --- /dev/null +++ b/tests/ui/dst/issue-113447.stderr @@ -0,0 +1,25 @@ +error[E0277]: can't compare `&[u8; 1]` with `[{integer}; 1]` + --> $DIR/issue-113447.rs:24:20 + | +LL | let _ = &[0u8] == [0xAA]; + | ^^ no implementation for `&[u8; 1] == [{integer}; 1]` + | + = help: the trait `PartialEq<[{integer}; 1]>` is not implemented for `&[u8; 1]` + = help: the following other types implement trait `PartialEq`: + <[A; N] as PartialEq<[B; N]>> + <[A; N] as PartialEq<[B]>> + <[A; N] as PartialEq<&[B]>> + <[A; N] as PartialEq<&mut [B]>> + <[T] as PartialEq>> + <[A] as PartialEq<[B]>> + <[B] as PartialEq<[A; N]>> + <&[u8] as PartialEq> + and 4 others +help: convert the array to a `&[u8]` slice instead + | +LL | let _ = &[0u8] == &[0xAA][..]; + | + ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr index 902053ecfef..b982be45196 100644 --- a/tests/ui/dyn-star/param-env-region-infer.current.stderr +++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/param-env-region-infer.rs:18:10 + --> $DIR/param-env-region-infer.rs:19:10 | LL | t as _ | ^ cannot infer type diff --git a/tests/ui/dyn-star/param-env-region-infer.next.stderr b/tests/ui/dyn-star/param-env-region-infer.next.stderr deleted file mode 100644 index 28aec533a00..00000000000 --- a/tests/ui/dyn-star/param-env-region-infer.next.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0391]: cycle detected when computing type of `make_dyn_star::{opaque#0}` - --> $DIR/param-env-region-infer.rs:16:60 - | -LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires type-checking `make_dyn_star`... - --> $DIR/param-env-region-infer.rs:16:1 - | -LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `make_dyn_star::{opaque#0}`... - = note: ...which requires normalizing `make_dyn_star::{opaque#0}`... - = note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle -note: cycle used when checking item types in top-level module - --> $DIR/param-env-region-infer.rs:10:1 - | -LL | / #![feature(dyn_star, pointer_like_trait)] -LL | | #![allow(incomplete_features)] -LL | | -LL | | use std::fmt::Debug; -... | -LL | | -LL | | fn main() {} - | |____________^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/dyn-star/param-env-region-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs index 537473abc3a..50dec94d25b 100644 --- a/tests/ui/dyn-star/param-env-region-infer.rs +++ b/tests/ui/dyn-star/param-env-region-infer.rs @@ -1,9 +1,10 @@ -// revisions: current next -// Need `-Zdeduplicate-diagnostics=yes` because the number of cycle errors -// emitted is for some horrible reason platform-specific. -//[next] compile-flags: -Ztrait-solver=next -Zdeduplicate-diagnostics=yes +// revisions: current // incremental +// FIXME(-Ztrait-solver=next): THis currently results in unstable query results: +// `normalizes-to(opaque, opaque)` changes from `Maybe(Ambiguous)` to `Maybe(Overflow)` +// once the hidden type of the opaque is already defined to be itself. + // checks that we don't ICE if there are region inference variables in the environment // when computing `PointerLike` builtin candidates. diff --git a/tests/ui/error-codes/E0608.stderr b/tests/ui/error-codes/E0608.stderr index 3aec509934b..f23f9977ba0 100644 --- a/tests/ui/error-codes/E0608.stderr +++ b/tests/ui/error-codes/E0608.stderr @@ -1,8 +1,8 @@ error[E0608]: cannot index into a value of type `u8` - --> $DIR/E0608.rs:2:5 + --> $DIR/E0608.rs:2:8 | LL | 0u8[2]; - | ^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.rs b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs new file mode 100644 index 00000000000..4d72962157b --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.rs @@ -0,0 +1,9 @@ +// The nested impl Trait references a higher-ranked region + +trait Trait<'a> { type Assoc; } +impl<'a> Trait<'a> for () { type Assoc = &'a str; } + +fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {} +//~^ ERROR captures lifetime that does not appear in bounds + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr new file mode 100644 index 00000000000..71d1d45f48b --- /dev/null +++ b/tests/ui/impl-trait/nested-rpit-hrtb-2.stderr @@ -0,0 +1,12 @@ +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/nested-rpit-hrtb-2.rs:6:57 + | +LL | fn test() -> impl for<'a> Trait<'a, Assoc = impl Sized> {} + | -- ---------- ^^ + | | | + | | opaque type defined here + | hidden type `&'a str` captures the lifetime `'a` as defined here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/index-bot.rs b/tests/ui/indexing/index-bot.rs similarity index 100% rename from tests/ui/index-bot.rs rename to tests/ui/indexing/index-bot.rs diff --git a/tests/ui/index-bot.stderr b/tests/ui/indexing/index-bot.stderr similarity index 78% rename from tests/ui/index-bot.stderr rename to tests/ui/indexing/index-bot.stderr index b5d78297505..bf231c92cad 100644 --- a/tests/ui/index-bot.stderr +++ b/tests/ui/indexing/index-bot.stderr @@ -1,8 +1,8 @@ error[E0608]: cannot index into a value of type `!` - --> $DIR/index-bot.rs:2:5 + --> $DIR/index-bot.rs:2:13 | LL | (return)[0]; - | ^^^^^^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/tests/ui/index-help.rs b/tests/ui/indexing/index-help.rs similarity index 100% rename from tests/ui/index-help.rs rename to tests/ui/indexing/index-help.rs diff --git a/tests/ui/index-help.stderr b/tests/ui/indexing/index-help.stderr similarity index 100% rename from tests/ui/index-help.stderr rename to tests/ui/indexing/index-help.stderr diff --git a/tests/ui/index_message.rs b/tests/ui/indexing/index_message.rs similarity index 100% rename from tests/ui/index_message.rs rename to tests/ui/indexing/index_message.rs diff --git a/tests/ui/index_message.stderr b/tests/ui/indexing/index_message.stderr similarity index 67% rename from tests/ui/index_message.stderr rename to tests/ui/indexing/index_message.stderr index 56d1d70809d..80f2bd52314 100644 --- a/tests/ui/index_message.stderr +++ b/tests/ui/indexing/index_message.stderr @@ -1,8 +1,8 @@ error[E0608]: cannot index into a value of type `({integer},)` - --> $DIR/index_message.rs:3:13 + --> $DIR/index_message.rs:3:14 | LL | let _ = z[0]; - | ^^^^ help: to access tuple elements, use: `z.0` + | ^^^ help: to access tuple elements, use: `.0` error: aborting due to previous error diff --git a/tests/ui/indexing-requires-a-uint.rs b/tests/ui/indexing/indexing-requires-a-uint.rs similarity index 100% rename from tests/ui/indexing-requires-a-uint.rs rename to tests/ui/indexing/indexing-requires-a-uint.rs diff --git a/tests/ui/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr similarity index 100% rename from tests/ui/indexing-requires-a-uint.stderr rename to tests/ui/indexing/indexing-requires-a-uint.stderr diff --git a/tests/ui/indexing/indexing-spans-caller-location.rs b/tests/ui/indexing/indexing-spans-caller-location.rs new file mode 100644 index 00000000000..2652f00211d --- /dev/null +++ b/tests/ui/indexing/indexing-spans-caller-location.rs @@ -0,0 +1,27 @@ +// run-pass + +// Regression test for https://github.com/rust-lang/rust/issues/114388 + +#[track_caller] +fn caller_line() -> u32 { + std::panic::Location::caller().line() +} + +fn main() { + let prev_line = caller_line(); // first line + (A { prev_line }) // second line + [0]; // third line +} + +struct A { + prev_line: u32, +} +impl std::ops::Index for A { + type Output = (); + + fn index(&self, _idx: usize) -> &() { + // Use the relative number to make it resistent to header changes. + assert_eq!(caller_line(), self.prev_line + 2); + &() + } +} diff --git a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr index 69c7491b2af..a0024c0920f 100644 --- a/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr +++ b/tests/ui/intrinsics/const-eval-select-backtrace-std.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at $DIR/const-eval-select-backtrace-std.rs:6:6: +thread 'main' panicked at $DIR/const-eval-select-backtrace-std.rs:6:8: byte index 1 is out of bounds of `` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/invalid/issue-114435-layout-type-err.rs b/tests/ui/invalid/issue-114435-layout-type-err.rs new file mode 100644 index 00000000000..a2d40593687 --- /dev/null +++ b/tests/ui/invalid/issue-114435-layout-type-err.rs @@ -0,0 +1,44 @@ +// build-fail +// compile-flags: --crate-type lib -Cdebuginfo=2 +// error-pattern: the type has an unknown layout + +#![recursion_limit = "10"] +macro_rules! link { + ($outer:ident, $inner:ident) => { + struct $outer($inner); + impl $outer { + fn new() -> $outer { + $outer($inner::new()) + } + } + impl std::ops::Deref for $outer { + type Target = $inner; + fn deref(&self) -> &$inner { + &self.0 + } + } + }; +} + +struct Bottom; + +impl Bottom { + fn new() -> Bottom { + Bottom + } +} + + +link!(A, B); +link!(B, C); +link!(C, D); +link!(D, E); +link!(E, F); +link!(F, G); +link!(G, H); +link!(H, I); +link!(I, J); +link!(J, K); +link!(K, Bottom); + +fn main() { } diff --git a/tests/ui/invalid/issue-114435-layout-type-err.stderr b/tests/ui/invalid/issue-114435-layout-type-err.stderr new file mode 100644 index 00000000000..a2db74ff8bd --- /dev/null +++ b/tests/ui/invalid/issue-114435-layout-type-err.stderr @@ -0,0 +1,8 @@ +error: reached the recursion limit finding the struct tail for `Bottom` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` + +error: the type has an unknown layout + +error: aborting due to 2 previous errors + diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr index 83333aa0c47..b18fe1512b5 100644 --- a/tests/ui/issues/issue-27842.stderr +++ b/tests/ui/issues/issue-27842.stderr @@ -1,24 +1,24 @@ error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})` - --> $DIR/issue-27842.rs:4:13 + --> $DIR/issue-27842.rs:4:16 | LL | let _ = tup[0]; - | ^^^^^^ help: to access tuple elements, use: `tup.0` + | ^^^ help: to access tuple elements, use: `.0` error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})` - --> $DIR/issue-27842.rs:9:13 + --> $DIR/issue-27842.rs:9:16 | LL | let _ = tup[i]; - | ^^^^-^ + | ^-^ | | | cannot access tuple elements at a variable index | = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) error[E0608]: cannot index into a value of type `({integer},)` - --> $DIR/issue-27842.rs:14:13 + --> $DIR/issue-27842.rs:14:16 | LL | let _ = tup[3]; - | ^^^^^^ + | ^^^ | = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) diff --git a/tests/ui/issues/issue-40861.stderr b/tests/ui/issues/issue-40861.stderr index 84e38b9bb05..9b6469d05e9 100644 --- a/tests/ui/issues/issue-40861.stderr +++ b/tests/ui/issues/issue-40861.stderr @@ -1,8 +1,8 @@ error[E0608]: cannot index into a value of type `()` - --> $DIR/issue-40861.rs:4:5 + --> $DIR/issue-40861.rs:4:7 | LL | ()[f(&[1.0])]; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`) diff --git a/tests/ui/lazy-type-alias/variance.rs b/tests/ui/lazy-type-alias/variance.rs new file mode 100644 index 00000000000..f83215856b8 --- /dev/null +++ b/tests/ui/lazy-type-alias/variance.rs @@ -0,0 +1,38 @@ +// This is a regression test for issue #114221. +// Check that we compute variances for lazy type aliases. + +// check-pass + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +// [+] `A` is covariant over `'a`. +struct A<'a>(Co<'a>); + +// [+] `Co` is covariant over `'a`. +type Co<'a> = &'a (); + +fn co<'a>(x: A<'static>) { + let _: A<'a> = x; +} + +// [-] `B` is contravariant over `'a`. +struct B<'a>(Contra<'a>); + +// [-] `Contra` is contravariant over `'a`. +type Contra<'a> = fn(&'a ()); + +fn contra<'a>(x: B<'a>) { + let _: B<'static> = x; +} + +struct C(CoContra); + +// [+, -] `CoContra` is covariant over `T` and contravariant over `U`. +type CoContra = Option<(T, fn(U))>; + +fn co_contra<'a>(x: C<&'static (), &'a ()>) -> C<&'a (), &'static ()> { + x +} + +fn main() {} diff --git a/tests/ui/lint/lint-unconditional-recursion.stderr b/tests/ui/lint/lint-unconditional-recursion.stderr index 9d200a7898e..d75754bf9f9 100644 --- a/tests/ui/lint/lint-unconditional-recursion.stderr +++ b/tests/ui/lint/lint-unconditional-recursion.stderr @@ -139,7 +139,7 @@ error: function cannot return without recursing LL | fn index(&self, x: usize) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | &self[x] - | ------- recursive call site + | --- recursive call site | = help: a `loop` may express intention better if this is on purpose diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs index e7da825ae36..b2d8a28d3c4 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.rs @@ -5,8 +5,8 @@ const s: usize = 42; const s_s: usize = 42; fn main() { - let s = "rust"; //~ ERROR identifier pair considered confusable - let s_s = "rust2"; //~ ERROR identifier pair considered confusable + let s = "rust"; //~ ERROR found both + let s_s = "rust2"; //~ ERROR found both not_affected(); } diff --git a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr index e9906c83d12..d1920f215e2 100644 --- a/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr +++ b/tests/ui/lint/rfc-2457-non-ascii-idents/lint-confusable-idents.stderr @@ -1,11 +1,11 @@ -error: identifier pair considered confusable between `s` and `s` +error: found both `s` and `s` as identifiers, which look alike --> $DIR/lint-confusable-idents.rs:8:9 | LL | const s: usize = 42; - | -- this is where the previous identifier occurred + | -- other identifier used here ... LL | let s = "rust"; - | ^ + | ^ this identifier can be confused with `s` | note: the lint level is defined here --> $DIR/lint-confusable-idents.rs:1:9 @@ -13,14 +13,14 @@ note: the lint level is defined here LL | #![deny(confusable_idents)] | ^^^^^^^^^^^^^^^^^ -error: identifier pair considered confusable between `s_s` and `s_s` +error: found both `s_s` and `s_s` as identifiers, which look alike --> $DIR/lint-confusable-idents.rs:9:9 | LL | const s_s: usize = 42; - | --- this is where the previous identifier occurred + | --- other identifier used here ... LL | let s_s = "rust2"; - | ^^^^^ + | ^^^^^ this identifier can be confused with `s_s` error: aborting due to 2 previous errors diff --git a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr index 22e7951dbe3..0bb486a8893 100644 --- a/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr +++ b/tests/ui/moves/use_of_moved_value_clone_suggestions.stderr @@ -8,7 +8,7 @@ LL | (t, t) | | | value moved here | -help: consider cloning the value if the performance cost is acceptable +help: clone the value to increment its reference count | LL | (t.clone(), t) | ++++++++ diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr index d1052ce3508..5f8076fc84d 100644 --- a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr @@ -9,7 +9,7 @@ note: required by a bound in `Sealed` | LL | pub trait Sealed: self::b::Hidden { | ^^^^^^^^^^^^^^^ required by this bound in `Sealed` - = note: `Sealed` is a "sealed trait", because to implement it you also need to implelement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it + = note: `Sealed` is a "sealed trait", because to implement it you also need to implement `a::b::Hidden`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it error: aborting due to previous error diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 4a2200091b2..e476a8024fd 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -18,7 +18,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*; #[macro_use /* 0#1 */] extern crate core /* 0#1 */; -extern crate compiler_builtins /* 443 */ as _ /* 0#1 */; +extern crate compiler_builtins /* 444 */ as _ /* 0#1 */; // Don't load unnecessary hygiene information from std extern crate std /* 0#0 */; diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 077a728a7a6..23a21004238 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*; #[macro_use /* 0#1 */] extern crate core /* 0#2 */; -extern crate compiler_builtins /* 443 */ as _ /* 0#2 */; +extern crate compiler_builtins /* 444 */ as _ /* 0#2 */; // Don't load unnecessary hygiene information from std extern crate std /* 0#0 */; diff --git a/tests/ui/span/suggestion-non-ascii.stderr b/tests/ui/span/suggestion-non-ascii.stderr index b14632d4e1b..21f8bb62a0c 100644 --- a/tests/ui/span/suggestion-non-ascii.stderr +++ b/tests/ui/span/suggestion-non-ascii.stderr @@ -1,8 +1,8 @@ error[E0608]: cannot index into a value of type `({integer},)` - --> $DIR/suggestion-non-ascii.rs:3:21 + --> $DIR/suggestion-non-ascii.rs:3:24 | LL | println!("☃{}", tup[0]); - | ^^^^^^ help: to access tuple elements, use: `tup.0` + | ^^^ help: to access tuple elements, use: `.0` error: aborting due to previous error diff --git a/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs new file mode 100644 index 00000000000..fcafdcf637a --- /dev/null +++ b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.rs @@ -0,0 +1,32 @@ +// compile-flags: -Ztrait-solver=next + +// Proving `W: Trait` instantiates `?0` with `(W, W)` and then +// proves `W: Trait` and `W: Trait`, resulting in a coinductive cycle. +// +// Proving coinductive cycles runs until we reach a fixpoint. This fixpoint is +// never reached here and each step doubles the amount of nested obligations. +// +// This previously caused a hang in the trait solver, see +// https://github.com/rust-lang/trait-system-refactor-initiative/issues/13. + +#![feature(rustc_attrs)] + +#[rustc_coinductive] +trait Trait {} + +struct W(T); + +impl Trait for W<(W, W)> +where + W: Trait, + W: Trait, +{ +} + +fn impls() {} + +fn main() { + impls::>(); + //~^ ERROR type annotations needed + //~| ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr new file mode 100644 index 00000000000..7d3535e1f01 --- /dev/null +++ b/tests/ui/traits/new-solver/coinduction/fixpoint-exponential-growth.stderr @@ -0,0 +1,23 @@ +error[E0282]: type annotations needed + --> $DIR/fixpoint-exponential-growth.rs:29:5 + | +LL | impls::>(); + | ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `impls` + +error[E0275]: overflow evaluating the requirement `W<_>: Trait` + --> $DIR/fixpoint-exponential-growth.rs:29:5 + | +LL | impls::>(); + | ^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`fixpoint_exponential_growth`) +note: required by a bound in `impls` + --> $DIR/fixpoint-exponential-growth.rs:26:13 + | +LL | fn impls() {} + | ^^^^^ required by this bound in `impls` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0275, E0282. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs new file mode 100644 index 00000000000..0cd14f05c8d --- /dev/null +++ b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.rs @@ -0,0 +1,69 @@ +// compile-flags: -Ztrait-solver=next +#![feature(rustc_attrs)] + +// This test is incredibly subtle. At its core the goal is to get a coinductive cycle, +// which, depending on its root goal, either holds or errors. We achieve this by getting +// incomplete inference via a `ParamEnv` candidate in the `A` impl and required +// inference from an `Impl` candidate in the `B` impl. +// +// To make global cache accesses stronger than the guidance from the where-bounds, we add +// another coinductive cycle from `A: Trait` to `A: Trait` and only +// constrain `D` directly. This means that any candidates which rely on `V` only make +// progress in the second iteration, allowing a cache access in the first iteration to take +// precedence. +// +// tl;dr: our caching of coinductive cycles was broken and this is a regression +// test for that. + +#[rustc_coinductive] +trait Trait {} +struct A(*const T); +struct B(*const T); + +trait IncompleteGuidance {} +impl IncompleteGuidance for T {} +impl IncompleteGuidance for T {} +impl IncompleteGuidance for T {} + +trait ImplGuidance {} +impl ImplGuidance for T {} +impl ImplGuidance for T {} + +impl Trait for A +where + T: IncompleteGuidance, + A: Trait, + B: Trait, + (): ToU8, +{ +} + +trait ToU8 {} +impl ToU8 for () {} + +impl Trait for B +where + T: ImplGuidance, + A: Trait, +{ +} + +fn impls_trait, U: ?Sized, V: ?Sized, D: ?Sized>() {} + +fn with_bound() +where + X: IncompleteGuidance, + X: IncompleteGuidance, + X: IncompleteGuidance, +{ + impls_trait::, _, _, _>(); // entering the cycle from `B` works + + // entering the cycle from `A` fails, but would work if we were to use the cache + // result of `B`. + impls_trait::, _, _, _>(); + //~^ ERROR the trait bound `A: Trait<_, _, _>` is not satisfied +} + +fn main() { + with_bound::(); +} diff --git a/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr new file mode 100644 index 00000000000..f1871ff0564 --- /dev/null +++ b/tests/ui/traits/new-solver/coinduction/incompleteness-unstable-result.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `A: Trait<_, _, _>` is not satisfied + --> $DIR/incompleteness-unstable-result.rs:63:19 + | +LL | impls_trait::, _, _, _>(); + | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A` + | + = help: the trait `Trait` is implemented for `A` +note: required by a bound in `impls_trait` + --> $DIR/incompleteness-unstable-result.rs:51:28 + | +LL | fn impls_trait, U: ?Sized, V: ?Sized, D: ?Sized>() {} + | ^^^^^^^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/overflow/global-cache.rs b/tests/ui/traits/new-solver/overflow/global-cache.rs new file mode 100644 index 00000000000..adc03da04a8 --- /dev/null +++ b/tests/ui/traits/new-solver/overflow/global-cache.rs @@ -0,0 +1,23 @@ +// compile-flags: -Ztrait-solver=next + +// Check that we consider the reached depth of global cache +// entries when detecting overflow. We would otherwise be unstable +// wrt to incremental compilation. +#![recursion_limit = "9"] + +trait Trait {} + +struct Inc(T); + +impl Trait for Inc {} +impl Trait for () {} + +fn impls_trait() {} + +type Four = Inc>>>; + +fn main() { + impls_trait::>>(); + impls_trait::>>>>(); + //~^ ERROR overflow evaluating the requirement +} diff --git a/tests/ui/traits/new-solver/overflow/global-cache.stderr b/tests/ui/traits/new-solver/overflow/global-cache.stderr new file mode 100644 index 00000000000..f3b86a083ad --- /dev/null +++ b/tests/ui/traits/new-solver/overflow/global-cache.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `Inc>>>>>>: Trait` + --> $DIR/global-cache.rs:21:5 + | +LL | impls_trait::>>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`) +note: required by a bound in `impls_trait` + --> $DIR/global-cache.rs:15:19 + | +LL | fn impls_trait() {} + | ^^^^^ required by this bound in `impls_trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/trait-upcasting/fewer-associated.rs b/tests/ui/traits/trait-upcasting/fewer-associated.rs new file mode 100644 index 00000000000..8228eea2681 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/fewer-associated.rs @@ -0,0 +1,25 @@ +// check-pass +// issue: 114035 +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(trait_upcasting)] + +trait A: B { + type Assoc; +} + +trait B {} + +fn upcast(a: &dyn A) -> &dyn B { + a +} + +// Make sure that we can drop the existential projection `A::Assoc = i32` +// when upcasting `dyn A` to `dyn B`. Before, we used some +// complicated algorithm which required rebuilding a new object type with +// different bounds in order to test that an upcast was valid, but this +// didn't allow upcasting to t that have fewer associated types +// than the source type. + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr new file mode 100644 index 00000000000..59c9d573705 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.current.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/illegal-upcast-from-impl.rs:16:66 + | +LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } + | ----------------------- ^ expected trait `Super`, found trait `Sub` + | | + | expected `&dyn Super` because of return type + | + = note: expected reference `&dyn Super` + found reference `&dyn Sub` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr new file mode 100644 index 00000000000..59c9d573705 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.next.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/illegal-upcast-from-impl.rs:16:66 + | +LL | fn illegal(x: &dyn Sub) -> &dyn Super { x } + | ----------------------- ^ expected trait `Super`, found trait `Sub` + | | + | expected `&dyn Super` because of return type + | + = note: expected reference `&dyn Super` + found reference `&dyn Sub` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs new file mode 100644 index 00000000000..774474281ea --- /dev/null +++ b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs @@ -0,0 +1,23 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(trait_upcasting)] + +trait Super { + type Assoc; +} + +trait Sub: Super {} + +impl Super for T { + type Assoc = i32; +} + +fn illegal(x: &dyn Sub) -> &dyn Super { x } +//~^ ERROR mismatched types + +// Want to make sure that we can't "upcast" to a supertrait that has a different +// associated type that is instead provided by a blanket impl (and doesn't come +// from the object bounds). + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/normalization.rs b/tests/ui/traits/trait-upcasting/normalization.rs new file mode 100644 index 00000000000..c78338b0da9 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/normalization.rs @@ -0,0 +1,20 @@ +// check-pass +// issue: 114113 +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(trait_upcasting)] + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +trait Bar {} +trait Foo: Bar<::Assoc> {} + +fn upcast(x: &dyn Foo) -> &dyn Bar { x } + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs index 2c740ccc1ae..fdd8fa65bd0 100644 --- a/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs +++ b/tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs @@ -1,5 +1,7 @@ #![feature(type_alias_impl_trait)] // check-pass +// revisions: default edition2021 +//[edition2021] compile-flags: --edition 2021 fn main() { type T = impl Copy; diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs new file mode 100644 index 00000000000..4a9631a7208 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +trait Trait<'a> { type Assoc; } +impl<'a> Trait<'a> for () { type Assoc = &'a str; } + +type WithoutLt = impl Sized; +fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {} +//~^ ERROR captures lifetime that does not appear in bounds + +type WithLt<'a> = impl Sized + 'a; +//~^ ERROR concrete type differs from previous defining opaque type use +fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {} +//~^ ERROR expected generic lifetime parameter, found `'a` + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr new file mode 100644 index 00000000000..9a783a6d92a --- /dev/null +++ b/tests/ui/type-alias-impl-trait/nested-tait-hrtb.stderr @@ -0,0 +1,35 @@ +error[E0700]: hidden type for `WithoutLt` captures lifetime that does not appear in bounds + --> $DIR/nested-tait-hrtb.rs:7:62 + | +LL | type WithoutLt = impl Sized; + | ---------- opaque type defined here +LL | fn without_lt() -> impl for<'a> Trait<'a, Assoc = WithoutLt> {} + | -- ^^ + | | + | hidden type `&'a str` captures the lifetime `'a` as defined here + +error[E0792]: expected generic lifetime parameter, found `'a` + --> $DIR/nested-tait-hrtb.rs:12:60 + | +LL | type WithLt<'a> = impl Sized + 'a; + | -- this generic parameter must be used with a generic lifetime parameter +LL | +LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {} + | ^^ + +error: concrete type differs from previous defining opaque type use + --> $DIR/nested-tait-hrtb.rs:10:19 + | +LL | type WithLt<'a> = impl Sized + 'a; + | ^^^^^^^^^^^^^^^ expected `&'a str`, got `{type error}` + | +note: previous use here + --> $DIR/nested-tait-hrtb.rs:12:17 + | +LL | fn with_lt() -> impl for<'a> Trait<'a, Assoc = WithLt<'a>> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0700, E0792. +For more information about an error, try `rustc --explain E0700`. diff --git a/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr b/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr index c55930da225..f81736245f3 100644 --- a/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr +++ b/tests/ui/typeck/issue-112252-ptr-arithmetics-help.stderr @@ -38,10 +38,10 @@ LL | let _c = unsafe { _ptr2.offset_from(_ptr1) }; | ++++++++ ~~~~~~~~~~~~~ +++ error[E0608]: cannot index into a value of type `*const u32` - --> $DIR/issue-112252-ptr-arithmetics-help.rs:9:14 + --> $DIR/issue-112252-ptr-arithmetics-help.rs:9:19 | LL | let _d = _ptr1[5]; - | ^^^^^^^^ + | ^^^ | help: consider using `wrapping_add` or `add` for indexing into raw pointer | diff --git a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs new file mode 100644 index 00000000000..da2dae1c46b --- /dev/null +++ b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.rs @@ -0,0 +1,15 @@ +struct RGB { + g: f64, + b: f64, +} + +fn main() { + let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone()); + //~^ ERROR cannot find value `e` in this scope + //~| ERROR cannot find value `e` in this scope + //~| ERROR mismatched types + let _ = RGB { r, g, b }; + //~^ ERROR cannot find value `g` in this scope + //~| ERROR struct `RGB` has no field named `r` + //~| ERROR mismatched types +} diff --git a/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr new file mode 100644 index 00000000000..4ccfacfb005 --- /dev/null +++ b/tests/ui/typeck/issue-114423-ice-regression-in-suggestion.stderr @@ -0,0 +1,52 @@ +error[E0425]: cannot find value `e` in this scope + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:51 + | +LL | let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone()); + | ^ not found in this scope + +error[E0425]: cannot find value `e` in this scope + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:62 + | +LL | let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone()); + | ^ not found in this scope + +error[E0425]: cannot find value `g` in this scope + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:22 + | +LL | let _ = RGB { r, g, b }; + | ^ help: a local variable with a similar name exists: `b` + +error[E0308]: mismatched types + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:7:50 + | +LL | let (r, alone_in_path, b): (f32, f32, f32) = (e.clone(), e.clone()); + | --------------- ^^^^^^^^^^^^^^^^^^^^^^ expected a tuple with 3 elements, found one with 2 elements + | | + | expected due to this + | + = note: expected tuple `(f32, f32, f32)` + found tuple `(f32, f32)` + +error[E0560]: struct `RGB` has no field named `r` + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:19 + | +LL | let _ = RGB { r, g, b }; + | ^ `RGB` does not have this field + | + = note: all struct fields are already assigned + +error[E0308]: mismatched types + --> $DIR/issue-114423-ice-regression-in-suggestion.rs:11:25 + | +LL | let _ = RGB { r, g, b }; + | ^ expected `f64`, found `f32` + | +help: you can convert an `f32` to an `f64` + | +LL | let _ = RGB { r, g, b: b.into() }; + | ++ +++++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0425, E0560. +For more information about an error, try `rustc --explain E0308`.