From b1a0c0b1231a554d4ae699221a80a6e2f81bac4d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 11:49:16 -0400 Subject: [PATCH 01/54] Change RTN to use .. again --- compiler/rustc_ast/src/ast.rs | 5 +++- compiler/rustc_ast/src/mut_visit.rs | 1 + compiler/rustc_ast/src/util/classify.rs | 2 +- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/messages.ftl | 3 ++ compiler/rustc_ast_lowering/src/errors.rs | 6 ++++ compiler/rustc_ast_lowering/src/lib.rs | 25 +++++++---------- compiler/rustc_ast_lowering/src/path.rs | 3 ++ .../rustc_ast_passes/src/ast_validation.rs | 7 +++-- compiler/rustc_ast_passes/src/feature_gate.rs | 24 ++-------------- compiler/rustc_ast_pretty/src/pprust/state.rs | 5 ++++ compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_parse/messages.ftl | 4 --- compiler/rustc_parse/src/errors.rs | 8 ------ compiler/rustc_parse/src/parser/path.rs | 27 ++++-------------- compiler/rustc_passes/src/hir_stats.rs | 2 +- compiler/rustc_resolve/src/late.rs | 1 + compiler/rustc_resolve/src/lib.rs | 1 + src/librustdoc/clean/types.rs | 2 +- tests/crashes/125249.rs | 2 +- .../bad-inputs-and-output.rs | 4 +-- .../bad-inputs-and-output.stderr | 12 ++++---- .../return-type-notation/basic.rs | 2 +- .../return-type-notation/equality.rs | 2 +- .../return-type-notation/equality.stderr | 4 +-- .../issue-120208-higher-ranked-const.rs | 2 +- .../issue-120208-higher-ranked-const.stderr | 4 +-- .../return-type-notation/missing.rs | 2 +- .../return-type-notation/missing.stderr | 2 +- .../return-type-notation/non-rpitit.rs | 2 +- .../return-type-notation/non-rpitit.stderr | 4 +-- .../issue-110963-early.rs | 2 +- .../return-type-notation/issue-110963-late.rs | 2 +- ...ormalizing-self-auto-trait-issue-109924.rs | 2 +- .../rtn-implied-in-supertrait.rs | 2 +- .../rtn-in-impl-signature.rs | 2 +- .../rtn-in-impl-signature.stderr | 12 ++++---- .../super-method-bound-ambig.rs | 2 +- .../super-method-bound-ambig.stderr | 4 +-- .../super-method-bound.rs | 2 +- .../return-type-notation/supertrait-bound.rs | 2 +- .../return-type-notation/ty-or-ct-params.rs | 2 +- .../ty-or-ct-params.stderr | 10 +++---- .../ui/borrowck/alias-liveness/rtn-static.rs | 4 +-- ...ature-gate-return_type_notation.cfg.stderr | 28 +++---------------- ...eature-gate-return_type_notation.no.stderr | 13 ++++----- .../feature-gate-return_type_notation.rs | 12 ++------ 47 files changed, 109 insertions(+), 163 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f5e79c04d784f..dbbc4980050de 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -176,6 +176,8 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), + /// `(..)` in return type notation + ParenthesizedElided(Span), } impl GenericArgs { @@ -187,6 +189,7 @@ impl GenericArgs { match self { AngleBracketed(data) => data.span, Parenthesized(data) => data.span, + ParenthesizedElided(span) => *span, } } } @@ -2051,7 +2054,7 @@ impl UintTy { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Clone, Encodable, Decodable, Debug)] pub struct AssocItemConstraint { pub id: NodeId, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 27e781a5a6385..f816375b912d6 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -582,6 +582,7 @@ fn noop_visit_generic_args(generic_args: &mut GenericArgs, vis: & match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), + GenericArgs::ParenthesizedElided(span) => vis.visit_span(span), } } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 4b2544ac47ed8..ed64f44f726fc 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -234,6 +234,6 @@ fn path_return_type(path: &ast::Path) -> Option<&ast::Ty> { ast::FnRetTy::Default(_) => None, ast::FnRetTy::Ty(ret) => Some(ret), }, - ast::GenericArgs::AngleBracketed(_) => None, + ast::GenericArgs::AngleBracketed(_) | ast::GenericArgs::ParenthesizedElided(_) => None, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 26cb04d4d47fc..f6929057bed13 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -609,6 +609,7 @@ where walk_list!(visitor, visit_ty, inputs); try_visit!(visitor.visit_fn_ret_ty(output)); } + GenericArgs::ParenthesizedElided(_span) => {} } V::Result::output() } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 58f65f1257fc7..d6eb344fd1dbb 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -36,6 +36,9 @@ ast_lowering_bad_return_type_notation_inputs = argument types not allowed with return type notation .suggestion = remove the input types +ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..` + .suggestion = add `..` + ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 3d4b6a1f033fb..6699c6e75f5ea 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -393,6 +393,12 @@ pub enum BadReturnTypeNotation { #[suggestion(code = "", applicability = "maybe-incorrect")] span: Span, }, + #[diag(ast_lowering_bad_return_type_notation_needs_dots)] + NeedsDots { + #[primary_span] + #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0a06304fcecfa..92fb5b3c2eb90 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -979,20 +979,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0 } GenericArgs::Parenthesized(data) => { - if data.inputs.is_empty() && matches!(data.output, FnRetTy::Default(..)) { - let parenthesized = if self.tcx.features().return_type_notation { - hir::GenericArgsParentheses::ReturnTypeNotation - } else { - self.emit_bad_parenthesized_trait_in_assoc_ty(data); - hir::GenericArgsParentheses::No - }; - GenericArgsCtor { - args: Default::default(), - constraints: &[], - parenthesized, - span: data.inputs_span, - } - } else if let Some(first_char) = constraint.ident.as_str().chars().next() + if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { let mut err = if !data.inputs.is_empty() { @@ -1004,7 +991,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: data.inputs_span.shrink_to_hi().to(ty.span), }) } else { - unreachable!("inputs are empty and return type is not provided") + self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + }) }; if !self.tcx.features().return_type_notation && self.tcx.sess.is_nightly_build() @@ -1034,6 +1023,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .0 } } + GenericArgs::ParenthesizedElided(span) => GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: *span, + }, }; gen_args_ctor.into_generic_args(self) } else { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 9d38e1e678471..1efa5bd3c4c6f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -276,6 +276,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } }, + GenericArgs::ParenthesizedElided(_span) => { + todo!() + } } } else { ( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ba4b6130b60c8..c0e8c4bf97789 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1289,6 +1289,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.with_impl_trait(None, |this| this.visit_ty(ty)); } } + GenericArgs::ParenthesizedElided(_span) => {} } } @@ -1445,7 +1446,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { span: args.span, }); } - None => {} + Some(ast::GenericArgs::ParenthesizedElided(_)) | None => {} } } } @@ -1693,7 +1694,9 @@ fn deny_equality_constraints( // Add `` to `Foo`. match &mut assoc_path.segments[len].args { Some(args) => match args.deref_mut() { - GenericArgs::Parenthesized(_) => continue, + GenericArgs::Parenthesized(_) | GenericArgs::ParenthesizedElided(..) => { + continue; + } GenericArgs::AngleBracketed(args) => { args.args.push(arg); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e1c1a027a30a7..9cf3182daea59 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; -use rustc_ast::{attr, AssocItemConstraint, AssocItemConstraintKind, NodeId}; +use rustc_ast::{attr, NodeId}; use rustc_ast::{token, PatKind}; use rustc_feature::{AttributeGate, BuiltinAttribute, Features, GateIssue, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::parse::{feature_err, feature_err_issue, feature_warn}; @@ -445,23 +445,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_fn(self, fn_kind) } - fn visit_assoc_item_constraint(&mut self, constraint: &'a AssocItemConstraint) { - if let AssocItemConstraintKind::Bound { .. } = constraint.kind - && let Some(ast::GenericArgs::Parenthesized(args)) = constraint.gen_args.as_ref() - && args.inputs.is_empty() - && let ast::FnRetTy::Default(..) = args.output - { - gate!( - &self, - return_type_notation, - constraint.span, - "return type notation is experimental" - ); - } - - visit::walk_assoc_item_constraint(self, constraint) - } - fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match &i.kind { ast::AssocItemKind::Fn(_) => true, @@ -566,6 +549,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { unsafe_extern_blocks, "`unsafe extern {}` blocks and `safe` keyword are experimental" ); + gate_all!(return_type_notation, "return type notation is experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { @@ -611,10 +595,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental"); gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental"); - // Despite being a new feature, `where T: Trait`, which is RTN syntax now, - // used to be gated under associated_type_bounds, which are right above, so RTN needs to - // be too. - gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental"); gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental"); gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable"); gate_all_legacy_dont_use!(auto_traits, "`auto` traits are unstable"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0225c95dca8e3..0568d368d8c4c 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1060,6 +1060,11 @@ impl<'a> PrintState<'a> for State<'a> { self.word(")"); self.print_fn_ret_ty(&data.output); } + ast::GenericArgs::ParenthesizedElided(_) => { + self.word("("); + self.word(".."); + self.word(")"); + } } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 22a6c06bba323..5b126d37ed645 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2413,7 +2413,7 @@ pub enum ImplItemKind<'hir> { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct AssocItemConstraint<'hir> { pub hir_id: HirId, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index f08efe60d96b8..e4c75ac11454a 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -45,10 +45,6 @@ parse_bad_assoc_type_bounds = bounds on associated types do not belong here parse_bad_item_kind = {$descr} is not supported in {$ctx} .help = consider moving the {$descr} out to a nearby module scope -parse_bad_return_type_notation_dotdot = - return type notation uses `()` instead of `(..)` for elided arguments - .suggestion = remove the `..` - parse_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 8d49887f16441..6894f470d88fd 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2567,14 +2567,6 @@ pub(crate) struct BadReturnTypeNotationOutput { pub span: Span, } -#[derive(Diagnostic)] -#[diag(parse_bad_return_type_notation_dotdot)] -pub(crate) struct BadReturnTypeNotationDotDot { - #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(parse_bad_assoc_type_bounds)] pub(crate) struct BadAssocTypeBounds { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index da8d1194325b4..03c647dd5278e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -353,18 +353,17 @@ impl<'a> Parser<'a> { })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() - } else if self.may_recover() - && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) // FIXME(return_type_notation): Could also recover `...` here. && self.look_ahead(1, |tok| tok.kind == token::DotDot) { - self.bump(); - self.dcx() - .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span }); - self.bump(); + self.bump(); // ( + self.bump(); // .. self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; let span = lo.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::return_type_notation, span); + if self.eat_noexpect(&token::RArrow) { let lo = self.prev_token.span; let ty = self.parse_ty()?; @@ -372,13 +371,7 @@ impl<'a> Parser<'a> { .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); } - ParenthesizedArgs { - span, - inputs: ThinVec::new(), - inputs_span: span, - output: ast::FnRetTy::Default(self.prev_token.span.shrink_to_hi()), - } - .into() + P(ast::GenericArgs::ParenthesizedElided(span)) } else { // `(T, U) -> R` @@ -733,14 +726,6 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); - if let AssocItemConstraintKind::Bound { .. } = kind - && let Some(ast::GenericArgs::Parenthesized(args)) = &gen_args - && args.inputs.is_empty() - && let ast::FnRetTy::Default(..) = args.output - { - self.psess.gated_spans.gate(sym::return_type_notation, span); - } - let constraint = AssocItemConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; Ok(Some(AngleBracketedArg::Constraint(constraint))) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 0ba61f8e8b40f..0720efebf9721 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -695,7 +695,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_generic_args(&mut self, g: &'v ast::GenericArgs) { record_variants!( (self, g, g, Id::None, ast, GenericArgs, GenericArgs), - [AngleBracketed, Parenthesized] + [AngleBracketed, Parenthesized, ParenthesizedElided] ); ast_visit::walk_generic_args(self, g) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 66a1c05289b7d..ad4e222f4deda 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1221,6 +1221,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } } } + GenericArgs::ParenthesizedElided(_) => {} } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 94cdce1025fe5..38963ef4ef092 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -350,6 +350,7 @@ impl<'a> From<&'a ast::PathSegment> for Segment { (args.span, found_lifetimes) } GenericArgs::Parenthesized(args) => (args.span, true), + GenericArgs::ParenthesizedElided(span) => (*span, true), } } else { (DUMMY_SP, false) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c4020f2a450bc..ddc3dd4270f7f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2557,7 +2557,7 @@ pub(crate) struct ProcMacro { /// * the `A: Bound` in `Trait` /// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy` /// * the `C = { Ct }` in `Trait` (feature `associated_const_equality`) -/// * the `f(): Bound` in `Trait` (feature `return_type_notation`) +/// * the `f(..): Bound` in `Trait` (feature `return_type_notation`) #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) struct AssocItemConstraint { pub(crate) assoc: PathSegment, diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs index 18196d7b34fe8..1cf6338a0d622 100644 --- a/tests/crashes/125249.rs +++ b/tests/crashes/125249.rs @@ -2,7 +2,7 @@ #![feature(return_position_impl_trait_in_trait, return_type_notation)] trait IntFactory { - fn stream(&self) -> impl IntFactory + Send>; + fn stream(&self) -> impl IntFactory + Send>; } pub fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index c23eff79ce2e5..a8c8a85c5aa68 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -13,7 +13,7 @@ fn foo>() {} fn bar (): Send>>() {} //~^ ERROR return type not allowed with return type notation -fn baz>() {} -//~^ ERROR return type notation uses `()` instead of `(..)` for elided arguments +fn baz>() {} +//~^ ERROR return type notation arguments must be elided with `..` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index d95249efe4049..7e1695984f1c3 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,9 +1,3 @@ -error: return type notation uses `()` instead of `(..)` for elided arguments - --> $DIR/bad-inputs-and-output.rs:16:24 - | -LL | fn baz>() {} - | ^^ help: remove the `..` - warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | @@ -25,5 +19,11 @@ error: return type not allowed with return type notation LL | fn bar (): Send>>() {} | ^^^^^^ help: remove the return type +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:16:23 + | +LL | fn baz>() {} + | ^^ help: add `..`: `(..)` + error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index 9755fd01c9764..be489a19a7ad2 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -17,7 +17,7 @@ async fn foo() -> Result<(), ()> { fn is_send(_: impl Send) {} fn test< - #[cfg(with)] T: Foo, + #[cfg(with)] T: Foo, #[cfg(without)] T: Foo, >() { is_send(foo::()); diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index ae38dce1818c9..95c16fa1e3f84 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -9,7 +9,7 @@ trait Trait { async fn method() {} } -fn test>>>() {} +fn test>>>() {} //~^ ERROR return type notation is not allowed to use type equality fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index d432e95773541..d76b1bd1c0510 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -10,8 +10,8 @@ LL | #![feature(return_type_notation)] error: return type notation is not allowed to use type equality --> $DIR/equality.rs:12:18 | -LL | fn test>>>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn test>>>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs index 11728b879900e..4d026b7d1d859 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs @@ -9,7 +9,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, //~^ ERROR return type notation is not allowed for functions that have const parameters { } diff --git a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr index 8a3f037d00321..12f32a75eda32 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.stderr @@ -13,8 +13,8 @@ error: return type notation is not allowed for functions that have const paramet LL | async fn check() -> bool; | -------------- const parameter declared here ... -LL | HC: HealthCheck + Send + 'static, - | ^^^^^^^^^^^^^ +LL | HC: HealthCheck + Send + 'static, + | ^^^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index 9a8b77d00b714..3a04a56339ba5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -7,7 +7,7 @@ trait Trait { async fn method() {} } -fn bar>() {} +fn bar>() {} //~^ ERROR associated function `methid` not found for `Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index db9cb9f49a305..5cb8e2642f51c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -10,7 +10,7 @@ LL | #![feature(return_type_notation)] error[E0220]: associated function `methid` not found for `Trait` --> $DIR/missing.rs:10:17 | -LL | fn bar>() {} +LL | fn bar>() {} | ^^^^^^ help: there is an associated function with a similar name: `method` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index db5f6fe389ea7..d283c6eab370d 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,7 @@ trait Trait { fn method() {} } -fn test>() {} +fn test>() {} //~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 3e307c5f42ca4..79ced3c96ed5c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -13,8 +13,8 @@ error: return type notation used on function that is not `async` and does not re LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^ +LL | fn test>() {} + | ^^^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 4090912f528c4..46b8fbf6f86e3 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -9,7 +9,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, { spawn(async move { let mut hc = hc; diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index e0e59b6c6adb2..cb9c0b97f1e99 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -10,7 +10,7 @@ trait HealthCheck { async fn do_health_check_par(hc: HC) where - HC: HealthCheck + Send + 'static, + HC: HealthCheck + Send + 'static, { spawn(async move { let mut hc = hc; diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs index bee9ad2516ee2..24041ed080752 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -16,7 +16,7 @@ impl Foo for Bar { async fn bar(&self) {} } -fn build(_: T) where T: Foo {} +fn build(_: T) where T: Foo {} fn main() { build(Bar); diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs index 365ca57400652..2f6e04c385384 100644 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs @@ -16,7 +16,7 @@ trait Foo { async fn bar(&self) -> i32; } -trait SendFoo: Foo + Send {} +trait SendFoo: Foo + Send {} fn foobar(foo: impl SendFoo) -> JoinHandle { spawn(async move { diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs index 637678692bd1f..1e971d0aea71d 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.rs @@ -7,7 +7,7 @@ trait Super1<'a> { fn bar<'b>() -> bool; } -impl Super1<'_, bar(): Send> for () {} +impl Super1<'_, bar(..): Send> for () {} //~^ ERROR associated item constraints are not allowed here //~| ERROR not all trait items implemented diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index 54960ae60bcca..b23dbc37a55cc 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -10,13 +10,13 @@ LL | #![feature(return_type_notation)] error[E0229]: associated item constraints are not allowed here --> $DIR/rtn-in-impl-signature.rs:10:17 | -LL | impl Super1<'_, bar(): Send> for () {} - | ^^^^^^^^^^^ associated item constraint not allowed here +LL | impl Super1<'_, bar(..): Send> for () {} + | ^^^^^^^^^^^^^ associated item constraint not allowed here | help: consider removing this associated item constraint | -LL | impl Super1<'_, bar(): Send> for () {} - | ~~~~~~~~~~~~~ +LL | impl Super1<'_, bar(..): Send> for () {} + | ~~~~~~~~~~~~~~~ error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/rtn-in-impl-signature.rs:10:1 @@ -24,8 +24,8 @@ error[E0046]: not all trait items implemented, missing: `bar` LL | fn bar<'b>() -> bool; | --------------------- `bar` from trait ... -LL | impl Super1<'_, bar(): Send> for () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation +LL | impl Super1<'_, bar(..): Send> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs index fa647ea0bc781..452568f3e4695 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs @@ -22,7 +22,7 @@ impl Foo for () {} fn test() where - T: Foo, + T: Foo, //~^ ERROR ambiguous associated function `test` in bounds of `Foo` { } diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr index 4003aad6d03c3..9a6fdd7f2ac6b 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr @@ -16,8 +16,8 @@ LL | async fn test(); LL | async fn test(); | ---------------- ambiguous `test` from `Super2` ... -LL | T: Foo, - | ^^^^^^^^^^^^ ambiguous associated function `test` +LL | T: Foo, + | ^^^^^^^^^^^^^^ ambiguous associated function `test` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index ad7ed5b283cf1..1aa8258a09b7d 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -16,7 +16,7 @@ impl Foo for () {} fn test() where - T: Foo, + T: Foo, { } diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index adb286a21d216..9c74c10b33319 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -6,6 +6,6 @@ trait IntFactory { fn stream(&self) -> impl Iterator; } -trait SendIntFactory: IntFactory + Send {} +trait SendIntFactory: IntFactory + Send {} fn main() {} diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 328cd8d2ad02e..06a966df4451a 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -11,7 +11,7 @@ trait Foo { fn test() where - T: Foo, + T: Foo, //~^ ERROR return type notation is not allowed for functions that have const parameters //~| ERROR return type notation is not allowed for functions that have type parameters { diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr index da94d9d1e6da4..1c000bc6c3318 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr @@ -13,17 +13,17 @@ error: return type notation is not allowed for functions that have type paramete LL | async fn bar() {} | - type parameter declared here ... -LL | T: Foo, - | ^^^^^^^^^^^ +LL | T: Foo, + | ^^^^^^^^^^^^^ error: return type notation is not allowed for functions that have const parameters - --> $DIR/ty-or-ct-params.rs:14:25 + --> $DIR/ty-or-ct-params.rs:14:27 | LL | async fn baz() {} | -------------- const parameter declared here ... -LL | T: Foo, - | ^^^^^^^^^^^ +LL | T: Foo, + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/borrowck/alias-liveness/rtn-static.rs b/tests/ui/borrowck/alias-liveness/rtn-static.rs index 37f634a8e23cd..6aa5d8fc7a107 100644 --- a/tests/ui/borrowck/alias-liveness/rtn-static.rs +++ b/tests/ui/borrowck/alias-liveness/rtn-static.rs @@ -7,7 +7,7 @@ trait Foo { fn borrow(&mut self) -> impl Sized + '_; } -fn live_past_borrow>(mut t: T) { +fn live_past_borrow>(mut t: T) { let x = t.borrow(); drop(t); drop(x); @@ -15,7 +15,7 @@ fn live_past_borrow>(mut t: T) { // Test that the `'_` item bound in `borrow` does not cause us to // overlook the `'static` RTN bound. -fn overlapping_mut>(mut t: T) { +fn overlapping_mut>(mut t: T) { let x = t.borrow(); let x = t.borrow(); } diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index 41bd66b13e70d..18f46928fab54 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -1,33 +1,13 @@ error[E0658]: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:14:17 + --> $DIR/feature-gate-return_type_notation.rs:10:18 | -LL | fn foo>() {} - | ^^^^^^^^^ +LL | fn foo>() {} + | ^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/feature-gate-return_type_notation.rs:14:17 - | -LL | fn foo>() {} - | ^-- - | | - | help: remove these parentheses - -error: expected type, found function - --> $DIR/feature-gate-return_type_notation.rs:14:17 - | -LL | fn foo>() {} - | ^ unexpected function - | -note: the associated function is defined here - --> $DIR/feature-gate-return_type_notation.rs:10:5 - | -LL | async fn m(); - | ^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr index 79c626cef35dc..18f46928fab54 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr @@ -1,14 +1,13 @@ -warning: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:14:17 +error[E0658]: return type notation is experimental + --> $DIR/feature-gate-return_type_notation.rs:10:18 | -LL | fn foo>() {} - | ^^^^^^^^^ +LL | fn foo>() {} + | ^^^^ | = note: see issue #109417 for more information = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = warning: unstable syntax can change at any point in the future, causing a hard error! - = note: for more information, see issue #65860 -warning: 1 warning emitted +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index 7ae6cd0234be3..254b794e431e9 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -1,21 +1,13 @@ //@ edition: 2021 //@ revisions: cfg no -//@ [no] check-pass -// Since we're not adding new syntax, `cfg`'d out RTN must pass. - - trait Trait { #[allow(async_fn_in_trait)] async fn m(); } #[cfg(cfg)] -fn foo>() {} -//[cfg]~^ ERROR return type notation is experimental -//[cfg]~| ERROR parenthesized generic arguments cannot be used in associated type constraints -//[cfg]~| ERROR expected type, found function -//[no]~^^^^ WARN return type notation is experimental -//[no]~| WARN unstable syntax can change at any point in the future, causing a hard error! +fn foo>() {} +//~^ ERROR return type notation is experimental fn main() {} From 82b4af7511a430e53d2ed554771754552e5ecca8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 14:10:32 -0400 Subject: [PATCH 02/54] Make sure we deny unimplemented RTN on qpath segments --- compiler/rustc_ast_lowering/messages.ftl | 2 + compiler/rustc_ast_lowering/src/errors.rs | 5 ++ compiler/rustc_ast_lowering/src/path.rs | 16 ++++- .../return-type-notation/bare-path.rs | 26 ++++++++ .../return-type-notation/bare-path.stderr | 66 +++++++++++++++++++ 5 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bare-path.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index d6eb344fd1dbb..9ed93d481e773 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -43,6 +43,8 @@ ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation .suggestion = remove the return type +ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet + ast_lowering_base_expression_double_dot = base expression required after `..` .suggestion = add a base expression here diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 6699c6e75f5ea..4c77892a6b753 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -399,6 +399,11 @@ pub enum BadReturnTypeNotation { #[suggestion(code = "(..)", applicability = "maybe-incorrect")] span: Span, }, + #[diag(ast_lowering_bad_return_type_notation_position)] + Position { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 1efa5bd3c4c6f..c6c08649374dd 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,7 +1,8 @@ use crate::ImplTraitPosition; use super::errors::{ - AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, GenericTypeWithParentheses, UseAngleBrackets, + AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, + GenericTypeWithParentheses, UseAngleBrackets, }; use super::ResolverAstLoweringExt; use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; @@ -276,8 +277,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } }, - GenericArgs::ParenthesizedElided(_span) => { - todo!() + GenericArgs::ParenthesizedElided(span) => { + self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + ( + GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: *span, + }, + false, + ) } } } else { diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs new file mode 100644 index 0000000000000..f507d82afec2f --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs @@ -0,0 +1,26 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Tr { + const CONST: usize; + + fn method() -> impl Sized; +} + +fn foo() +where + T::method(..): Send, + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected type, found function + ::method(..): Send, + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected associated type, found associated function `Tr::method` +{ + let _ = T::CONST::(..); + //~^ ERROR return type notation not allowed in this position yet + let _: T::method(..); + //~^ ERROR return type notation not allowed in this position yet + //~| ERROR expected type, found function +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr new file mode 100644 index 0000000000000..cb45de59c7e23 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr @@ -0,0 +1,66 @@ +error[E0575]: expected associated type, found associated function `Tr::method` + --> $DIR/bare-path.rs:15:5 + | +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^ not a associated type + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bare-path.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:19:23 + | +LL | let _ = T::CONST::(..); + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:21:21 + | +LL | let _: T::method(..); + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:12:14 + | +LL | T::method(..): Send, + | ^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:15:22 + | +LL | ::method(..): Send, + | ^^^^ + +error: expected type, found function + --> $DIR/bare-path.rs:12:8 + | +LL | T::method(..): Send, + | ^^^^^^ unexpected function + | +note: the associated function is defined here + --> $DIR/bare-path.rs:7:5 + | +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected type, found function + --> $DIR/bare-path.rs:21:15 + | +LL | let _: T::method(..); + | ^^^^^^ unexpected function + | +note: the associated function is defined here + --> $DIR/bare-path.rs:7:5 + | +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0575`. From 99365a5a7ace1092852784c2fa71b7fd5ef25e5d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 28 Jun 2024 14:18:36 -0400 Subject: [PATCH 03/54] Implement RTN support in rustfmt --- src/tools/rustfmt/src/types.rs | 34 +++++++++++-------- .../tests/target/return-type-notation.rs | 10 ++++++ 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 src/tools/rustfmt/tests/target/return-type-notation.rs diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index c0bf9482b1143..c826547e9d001 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -484,21 +484,25 @@ fn rewrite_generic_args( span: Span, ) -> Option { match gen_args { - ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => { - let args = data - .args - .iter() - .map(|x| match x { - ast::AngleBracketedArg::Arg(generic_arg) => { - SegmentParam::from_generic_arg(generic_arg) - } - ast::AngleBracketedArg::Constraint(constraint) => { - SegmentParam::Binding(constraint) - } - }) - .collect::>(); + ast::GenericArgs::AngleBracketed(ref data) => { + if data.args.is_empty() { + Some("".to_owned()) + } else { + let args = data + .args + .iter() + .map(|x| match x { + ast::AngleBracketedArg::Arg(generic_arg) => { + SegmentParam::from_generic_arg(generic_arg) + } + ast::AngleBracketedArg::Constraint(constraint) => { + SegmentParam::Binding(constraint) + } + }) + .collect::>(); - overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span) + overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span) + } } ast::GenericArgs::Parenthesized(ref data) => format_function_type( data.inputs.iter().map(|x| &**x), @@ -508,7 +512,7 @@ fn rewrite_generic_args( context, shape, ), - _ => Some("".to_owned()), + ast::GenericArgs::ParenthesizedElided(..) => Some("(..)".to_owned()), } } diff --git a/src/tools/rustfmt/tests/target/return-type-notation.rs b/src/tools/rustfmt/tests/target/return-type-notation.rs new file mode 100644 index 0000000000000..0f26e7e272b8b --- /dev/null +++ b/src/tools/rustfmt/tests/target/return-type-notation.rs @@ -0,0 +1,10 @@ +fn rtn() +where + T: Trait, + T::method(..): Send + 'static, +{ +} + +fn test() { + let x: T::method(..); +} From c54a2a53f83d9eb4fec161ecc304164d0303fbfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 27 Jun 2024 19:03:47 +0200 Subject: [PATCH 04/54] Make mtime of reproducible tarball dependent on git commit --- src/bootstrap/src/utils/tarball.rs | 26 ++++++++++++++++++++++- src/tools/rust-installer/src/tarballer.rs | 18 ++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 5cc319826dbf3..3c15bb296f39a 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -9,9 +9,9 @@ use std::path::{Path, PathBuf}; use crate::core::builder::Builder; use crate::core::{build_steps::dist::distdir, builder::Kind}; -use crate::utils::channel; use crate::utils::exec::BootstrapCommand; use crate::utils::helpers::{move_file, t}; +use crate::utils::{channel, helpers}; #[derive(Copy, Clone)] pub(crate) enum OverlayKind { @@ -351,6 +351,30 @@ impl<'a> Tarball<'a> { }; cmd.args(["--compression-profile", compression_profile]); + + // We want to use a pinned modification time for files in the archive + // to achieve better reproducibility. However, using the same mtime for all + // releases is not ideal, because it can break e.g. Cargo mtime checking + // (https://github.com/rust-lang/rust/issues/125578). + // Therefore, we set mtime to the date of the latest commit (if we're managed + // by git). In this way, the archive will still be always the same for a given commit + // (achieving reproducibility), but it will also change between different commits and + // Rust versions, so that it won't break mtime-based caches. + // + // Note that this only overrides the mtime of files, not directories, due to the + // limitations of the tarballer tool. Directories will have their mtime set to 2006. + + // Get the UTC timestamp of the last git commit, if we're under git. + // We need to use UTC, so that anyone who tries to rebuild from the same commit + // gets the same timestamp. + if self.builder.rust_info().is_managed_git_subrepository() { + // %ct means committer date + let timestamp = helpers::output( + helpers::git(Some(&self.builder.src)).arg("log").arg("-1").arg("--format=%ct"), + ); + cmd.args(["--override-file-mtime", timestamp.trim()]); + } + self.builder.run(cmd); // Ensure there are no symbolic links in the tarball. In particular, diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs index 2f093e7ad17fd..b5e87a66ffc39 100644 --- a/src/tools/rust-installer/src/tarballer.rs +++ b/src/tools/rust-installer/src/tarballer.rs @@ -32,6 +32,12 @@ actor! { /// The formats used to compress the tarball. #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -65,6 +71,8 @@ impl Tarballer { let buf = BufWriter::with_capacity(1024 * 1024, encoder); let mut builder = Builder::new(buf); // Make uid, gid and mtime deterministic to improve reproducibility + // The modification time of directories will be set to the date of the first Rust commit. + // The modification time of files will be set to `override_file_mtime` (see `append_path`). builder.mode(HeaderMode::Deterministic); let pool = rayon::ThreadPoolBuilder::new().num_threads(2).build().unwrap(); @@ -77,7 +85,7 @@ impl Tarballer { } for path in files { let src = Path::new(&self.work_dir).join(&path); - append_path(&mut builder, &src, &path) + append_path(&mut builder, &src, &path, self.override_file_mtime) .with_context(|| format!("failed to tar file '{}'", src.display()))?; } builder @@ -93,10 +101,16 @@ impl Tarballer { } } -fn append_path(builder: &mut Builder, src: &Path, path: &String) -> Result<()> { +fn append_path( + builder: &mut Builder, + src: &Path, + path: &String, + override_file_mtime: u64, +) -> Result<()> { let stat = symlink_metadata(src)?; let mut header = Header::new_gnu(); header.set_metadata_in_mode(&stat, HeaderMode::Deterministic); + header.set_mtime(override_file_mtime); if stat.file_type().is_symlink() { let link = read_link(src)?; From e1999f9a0815c891d71588045b96a76e8e2c45a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 29 Jun 2024 23:30:57 +0200 Subject: [PATCH 05/54] Add support for mtime override to `generate` and `combine` rust-installer commands --- src/tools/rust-installer/src/combiner.rs | 9 ++++++++- src/tools/rust-installer/src/generator.rs | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs index 565d19d863f64..c211b34850a07 100644 --- a/src/tools/rust-installer/src/combiner.rs +++ b/src/tools/rust-installer/src/combiner.rs @@ -55,6 +55,12 @@ actor! { /// The formats used to compress the tarball #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -145,7 +151,8 @@ impl Combiner { .input(self.package_name) .output(path_to_str(&output)?.into()) .compression_profile(self.compression_profile) - .compression_formats(self.compression_formats); + .compression_formats(self.compression_formats) + .override_file_mtime(self.override_file_mtime); tarballer.run()?; Ok(()) diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs index b101e67d8df7f..035a394deebe6 100644 --- a/src/tools/rust-installer/src/generator.rs +++ b/src/tools/rust-installer/src/generator.rs @@ -61,6 +61,12 @@ actor! { /// The formats used to compress the tarball #[arg(value_name = "FORMAT", default_value_t)] compression_formats: CompressionFormats, + + /// Modification time that will be set for all files added to the archive. + /// The default is the date of the first Rust commit from 2006. + /// This serves for better reproducibility of the archives. + #[arg(value_name = "FILE_MTIME", default_value_t = 1153704088)] + override_file_mtime: u64, } } @@ -114,7 +120,8 @@ impl Generator { .input(self.package_name) .output(path_to_str(&output)?.into()) .compression_profile(self.compression_profile) - .compression_formats(self.compression_formats); + .compression_formats(self.compression_formats) + .override_file_mtime(self.override_file_mtime); tarballer.run()?; Ok(()) From 8127461b0ed54dea8ca9cf430b1d231611e1b477 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:01:55 +0000 Subject: [PATCH 06/54] Move -Zprint-type-sizes and -Zprint-vtable-sizes into codegen_and_build_linker --- compiler/rustc_driver_impl/src/lib.rs | 17 +---------------- compiler/rustc_interface/src/queries.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bbe9741bf444e..3780e575b9352 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -41,7 +41,6 @@ use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::collect_crate_types; use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; use rustc_span::FileName; @@ -448,21 +447,7 @@ fn run_compiler( return early_exit(); } - let linker = queries.codegen_and_build_linker()?; - - // This must run after monomorphization so that all generic types - // have been instantiated. - if sess.opts.unstable_opts.print_type_sizes { - sess.code_stats.print_type_sizes(); - } - - if sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = queries.global_ctxt()?.enter(|tcx| tcx.crate_name(LOCAL_CRATE)); - - sess.code_stats.print_vtable_sizes(crate_name); - } - - Ok(Some(linker)) + Ok(Some(queries.codegen_and_build_linker()?)) })?; // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index cfd4304e89303..5f00d7a76b29b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -121,6 +121,18 @@ impl<'tcx> Queries<'tcx> { self.global_ctxt()?.enter(|tcx| { let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?; + // This must run after monomorphization so that all generic types + // have been instantiated. + if tcx.sess.opts.unstable_opts.print_type_sizes { + tcx.sess.code_stats.print_type_sizes(); + } + + if tcx.sess.opts.unstable_opts.print_vtable_sizes { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + tcx.sess.code_stats.print_vtable_sizes(crate_name); + } + Ok(Linker { dep_graph: tcx.dep_graph.clone(), output_filenames: tcx.output_filenames(()).clone(), From da81d0d940481827fb2bdd164ea0038832e3779e Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 1 Jul 2024 06:03:08 +0800 Subject: [PATCH 07/54] Update LLVM submodule --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 5a5152f653959..e6a6470d1eb4c 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 5a5152f653959d14d68613a3a8a033fb65eec021 +Subproject commit e6a6470d1eb4c88fee4b1ea98cd8e0ac4a181c16 From 15fbe618a14ddde520561c4cf1b85d4e4c9005f8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 09:34:52 -0700 Subject: [PATCH 08/54] rustdoc: update to pulldown-cmark 0.11 --- Cargo.lock | 21 ++-- compiler/rustc_resolve/Cargo.toml | 2 +- compiler/rustc_resolve/src/rustdoc.rs | 14 ++- src/librustdoc/html/markdown.rs | 111 +++++++++--------- src/librustdoc/passes/lint/bare_urls.rs | 4 +- src/librustdoc/passes/lint/html_tags.rs | 6 +- .../passes/lint/redundant_explicit_links.rs | 16 ++- src/tools/tidy/src/deps.rs | 1 + 8 files changed, 94 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94d70a020a4dc..3af90a252aea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3123,25 +3123,26 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.6" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ "bitflags 2.5.0", + "getopts", "memchr", + "pulldown-cmark-escape 0.10.1", "unicase", ] [[package]] name = "pulldown-cmark" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +checksum = "8746739f11d39ce5ad5c2520a9b75285310dbfe78c541ccf832d38615765aec0" dependencies = [ "bitflags 2.5.0", - "getopts", "memchr", - "pulldown-cmark-escape", + "pulldown-cmark-escape 0.11.0", "unicase", ] @@ -3151,6 +3152,12 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" +[[package]] +name = "pulldown-cmark-escape" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" + [[package]] name = "pulldown-cmark-to-cmark" version = "13.0.0" @@ -4604,7 +4611,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags 2.5.0", - "pulldown-cmark 0.9.6", + "pulldown-cmark 0.11.0", "rustc_arena", "rustc_ast", "rustc_ast_pretty", diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index b6ae54010c242..b71853b871dc5 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -pulldown-cmark = { version = "0.9.6", default-features = false } +pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 66b4981eb55ba..594608153211d 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -1,4 +1,6 @@ -use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, Options, Parser, Tag}; +use pulldown_cmark::{ + BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, Options, Parser, Tag, +}; use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; @@ -427,7 +429,9 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { while let Some(event) = event_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + Event::Start(Tag::Link { link_type, dest_url, title: _, id: _ }) + if may_be_doc_link(link_type) => + { if matches!( link_type, LinkType::Inline @@ -441,7 +445,7 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } } - links.push(preprocess_link(&dest)); + links.push(preprocess_link(&dest_url)); } _ => {} } @@ -451,8 +455,8 @@ fn parse_links<'md>(doc: &'md str) -> Vec> { } /// Collects additional data of link. -fn collect_link_data<'input, 'callback>( - event_iter: &mut Parser<'input, 'callback>, +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + event_iter: &mut Parser<'input, F>, ) -> Option> { let mut display_text: Option = None; let mut append_text = |text: CowStr<'_>| { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index bae929c64eab2..a7f0df5afa98f 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -54,7 +54,8 @@ use crate::html::render::small_url_encode; use crate::html::toc::TocBuilder; use pulldown_cmark::{ - html, BrokenLink, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, Options, Parser, Tag, + html, BrokenLink, BrokenLinkCallback, CodeBlockKind, CowStr, Event, LinkType, OffsetIter, + Options, Parser, Tag, TagEnd, }; #[cfg(test)] @@ -230,7 +231,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let mut original_text = String::new(); for event in &mut self.inner { match event { - Event::End(Tag::CodeBlock(..)) => break, + Event::End(TagEnd::CodeBlock) => break, Event::Text(ref s) => { original_text.push_str(s); } @@ -359,16 +360,17 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { match &mut event { // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` // Remove any disambiguator. - Some(Event::Start(Tag::Link( + Some(Event::Start(Tag::Link { // [fn@f] or [fn@f][] - LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, - dest, + link_type: LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest_url, title, - ))) => { - debug!("saw start of shortcut link to {dest} with title {title}"); + .. + })) => { + debug!("saw start of shortcut link to {dest_url} with title {title}"); // If this is a shortcut link, it was resolved by the broken_link_callback. // So the URL will already be updated properly. - let link = self.links.iter().find(|&link| *link.href == **dest); + let link = self.links.iter().find(|&link| *link.href == **dest_url); // Since this is an external iterator, we can't replace the inner text just yet. // Store that we saw a link so we know to replace it later. if let Some(link) = link { @@ -381,16 +383,9 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } } // Now that we're done with the shortcut link, don't replace any more text. - Some(Event::End(Tag::Link( - LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, - dest, - _, - ))) => { - debug!("saw end of shortcut link to {dest}"); - if self.links.iter().any(|link| *link.href == **dest) { - assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); - self.shortcut_link = None; - } + Some(Event::End(TagEnd::Link)) if self.shortcut_link.is_some() => { + debug!("saw end of shortcut link"); + self.shortcut_link = None; } // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. // [`fn@f`] @@ -433,9 +428,11 @@ impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { } // If this is a link, but not a shortcut link, // replace the URL, since the broken_link_callback was not called. - Some(Event::Start(Tag::Link(_, dest, title))) => { - if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { - *dest = CowStr::Borrowed(link.href.as_ref()); + Some(Event::Start(Tag::Link { dest_url, title, .. })) => { + if let Some(link) = + self.links.iter().find(|&link| *link.original_text == **dest_url) + { + *dest_url = CowStr::Borrowed(link.href.as_ref()); if title.is_empty() && !link.tooltip.is_empty() { *title = CowStr::Borrowed(link.tooltip.as_ref()); } @@ -477,9 +474,9 @@ impl<'a, I: Iterator>> Iterator for TableWrapper<'a, I> { self.stored_events.push_back(Event::Start(Tag::Table(t))); Event::Html(CowStr::Borrowed("
")) } - Event::End(Tag::Table(t)) => { + Event::End(TagEnd::Table) => { self.stored_events.push_back(Event::Html(CowStr::Borrowed("
"))); - Event::End(Tag::Table(t)) + Event::End(TagEnd::Table) } e => e, }) @@ -519,11 +516,11 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator } let event = self.inner.next(); - if let Some((Event::Start(Tag::Heading(level, _, _)), _)) = event { + if let Some((Event::Start(Tag::Heading { level, .. }), _)) = event { let mut id = String::new(); for event in &mut self.inner { match &event.0 { - Event::End(Tag::Heading(..)) => break, + Event::End(TagEnd::Heading(_)) => break, Event::Text(text) | Event::Code(text) => { id.extend(text.chars().filter_map(slugify)); self.buf.push_back(event); @@ -566,27 +563,27 @@ impl<'a, I: Iterator>> SummaryLine<'a, I> { } } -fn check_if_allowed_tag(t: &Tag<'_>) -> bool { +fn check_if_allowed_tag(t: &TagEnd) -> bool { matches!( t, - Tag::Paragraph - | Tag::Emphasis - | Tag::Strong - | Tag::Strikethrough - | Tag::Link(..) - | Tag::BlockQuote + TagEnd::Paragraph + | TagEnd::Emphasis + | TagEnd::Strong + | TagEnd::Strikethrough + | TagEnd::Link + | TagEnd::BlockQuote ) } -fn is_forbidden_tag(t: &Tag<'_>) -> bool { +fn is_forbidden_tag(t: &TagEnd) -> bool { matches!( t, - Tag::CodeBlock(_) - | Tag::Table(_) - | Tag::TableHead - | Tag::TableRow - | Tag::TableCell - | Tag::FootnoteDefinition(_) + TagEnd::CodeBlock + | TagEnd::Table + | TagEnd::TableHead + | TagEnd::TableRow + | TagEnd::TableCell + | TagEnd::FootnoteDefinition ) } @@ -604,12 +601,12 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { let mut is_start = true; let is_allowed_tag = match event { Event::Start(ref c) => { - if is_forbidden_tag(c) { + if is_forbidden_tag(&c.to_end()) { self.skipped_tags += 1; return None; } self.depth += 1; - check_if_allowed_tag(c) + check_if_allowed_tag(&c.to_end()) } Event::End(ref c) => { if is_forbidden_tag(c) { @@ -633,7 +630,7 @@ impl<'a, I: Iterator>> Iterator for SummaryLine<'a, I> { if is_start { Some(Event::Start(Tag::Paragraph)) } else { - Some(Event::End(Tag::Paragraph)) + Some(Event::End(TagEnd::Paragraph)) } } else { Some(event) @@ -679,7 +676,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => { let mut content = Vec::new(); for (event, _) in &mut self.inner { - if let Event::End(Tag::FootnoteDefinition(..)) = event { + if let Event::End(TagEnd::FootnoteDefinition) = event { break; } content.push(event); @@ -696,7 +693,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { for (mut content, id) in v { write!(ret, "
  • ").unwrap(); let mut is_paragraph = false; - if let Some(&Event::End(Tag::Paragraph)) = content.last() { + if let Some(&Event::End(TagEnd::Paragraph)) = content.last() { content.pop(); is_paragraph = true; } @@ -806,7 +803,7 @@ pub(crate) fn find_codes( tests.visit_test(text, block_info, line); prev_offset = offset.start; } - Event::Start(Tag::Heading(level, _, _)) => { + Event::Start(Tag::Heading { level, .. }) => { register_header = Some(level as u32); } Event::Text(ref s) if register_header.is_some() => { @@ -1432,7 +1429,7 @@ impl MarkdownItemInfo<'_> { // Treat inline HTML as plain text. let p = p.map(|event| match event.0 { - Event::Html(text) => (Event::Text(text), event.1), + Event::Html(text) | Event::InlineHtml(text) => (Event::Text(text), event.1), _ => event, }); @@ -1442,7 +1439,7 @@ impl MarkdownItemInfo<'_> { let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = p.filter(|event| { - !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) + !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph)) }); html::push_html(&mut s, p); @@ -1472,7 +1469,7 @@ impl MarkdownSummaryLine<'_> { let mut s = String::new(); let without_paragraphs = LinkReplacer::new(&mut summary, links).filter(|event| { - !matches!(event, Event::Start(Tag::Paragraph) | Event::End(Tag::Paragraph)) + !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph)) }); html::push_html(&mut s, without_paragraphs); @@ -1544,8 +1541,8 @@ fn markdown_summary_with_limit( _ => {} }, Event::End(tag) => match tag { - Tag::Emphasis | Tag::Strong => buf.close_tag(), - Tag::Paragraph | Tag::Heading(..) => return ControlFlow::Break(()), + TagEnd::Emphasis | TagEnd::Strong => buf.close_tag(), + TagEnd::Paragraph | TagEnd::Heading(_) => return ControlFlow::Break(()), _ => {} }, Event::HardBreak | Event::SoftBreak => buf.push(" ")?, @@ -1605,8 +1602,8 @@ pub(crate) fn plain_text_summary(md: &str, link_names: &[RenderedLink]) -> Strin } Event::HardBreak | Event::SoftBreak => s.push(' '), Event::Start(Tag::CodeBlock(..)) => break, - Event::End(Tag::Paragraph) => break, - Event::End(Tag::Heading(..)) => break, + Event::End(TagEnd::Paragraph) => break, + Event::End(TagEnd::Heading(..)) => break, _ => (), } } @@ -1765,7 +1762,7 @@ pub(crate) fn markdown_links<'md, R>( while let Some((event, span)) = event_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) if may_be_doc_link(link_type) => { + Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => { let range = match link_type { // Link is pulled from the link itself. LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => { @@ -1775,7 +1772,7 @@ pub(crate) fn markdown_links<'md, R>( LinkType::Inline => span_for_offset_backward(span, b'(', b')'), // Link is pulled from elsewhere in the document. LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => { - span_for_link(&dest, span) + span_for_link(&dest_url, span) } LinkType::Autolink | LinkType::Email => unreachable!(), }; @@ -1795,7 +1792,7 @@ pub(crate) fn markdown_links<'md, R>( if let Some(link) = preprocess_link(MarkdownLink { kind: link_type, - link: dest.into_string(), + link: dest_url.into_string(), display_text, range, }) { @@ -1810,8 +1807,8 @@ pub(crate) fn markdown_links<'md, R>( } /// Collects additional data of link. -fn collect_link_data<'input, 'callback>( - event_iter: &mut OffsetIter<'input, 'callback>, +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + event_iter: &mut OffsetIter<'input, F>, ) -> Option { let mut display_text: Option = None; let mut append_text = |text: CowStr<'_>| { diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 8f68f6ff4764a..4b2d3092837e1 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -42,11 +42,11 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { match event { Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag), // We don't want to check the text inside code blocks or links. - Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link(..))) => { + Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => { while let Some((event, _)) = p.next() { match event { Event::End(end) - if mem::discriminant(&end) == mem::discriminant(&tag) => + if mem::discriminant(&end) == mem::discriminant(&tag.to_end()) => { break; } diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index a0064a9011254..87dfa5d5389d7 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -4,7 +4,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag}; +use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag, TagEnd}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use std::iter::Peekable; @@ -140,10 +140,10 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { for (event, range) in p { match event { Event::Start(Tag::CodeBlock(_)) => in_code_block = true, - Event::Html(text) if !in_code_block => { + Event::Html(text) | Event::InlineHtml(text) if !in_code_block => { extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) } - Event::End(Tag::CodeBlock(_)) => in_code_block = false, + Event::End(TagEnd::CodeBlock) => in_code_block = false, _ => {} } } diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 7ab974046b9c7..b36b41c9f2d2e 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -1,6 +1,8 @@ use std::ops::Range; -use pulldown_cmark::{BrokenLink, CowStr, Event, LinkType, OffsetIter, Parser, Tag}; +use pulldown_cmark::{ + BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag, +}; use rustc_ast::NodeId; use rustc_errors::SuggestionStyle; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; @@ -95,7 +97,7 @@ fn check_redundant_explicit_link<'md>( while let Some((event, link_range)) = offset_iter.next() { match event { - Event::Start(Tag::Link(link_type, dest, _)) => { + Event::Start(Tag::Link { link_type, dest_url, .. }) => { let link_data = collect_link_data(&mut offset_iter); if let Some(resolvable_link) = link_data.resolvable_link.as_ref() { @@ -108,7 +110,7 @@ fn check_redundant_explicit_link<'md>( } } - let explicit_link = dest.to_string(); + let explicit_link = dest_url.to_string(); let display_link = link_data.resolvable_link.clone()?; if explicit_link.ends_with(&display_link) || display_link.ends_with(&explicit_link) @@ -122,7 +124,7 @@ fn check_redundant_explicit_link<'md>( doc, resolutions, link_range, - dest.to_string(), + dest_url.to_string(), link_data, if link_type == LinkType::Inline { (b'(', b')') @@ -139,7 +141,7 @@ fn check_redundant_explicit_link<'md>( doc, resolutions, link_range, - &dest, + &dest_url, link_data, ); } @@ -259,7 +261,9 @@ fn find_resolution(resolutions: &DocLinkResMap, path: &str) -> Option) -> LinkData { +fn collect_link_data<'input, F: BrokenLinkCallback<'input>>( + offset_iter: &mut OffsetIter<'input, F>, +) -> LinkData { let mut resolvable_link = None; let mut resolvable_link_range = None; let mut display_link = String::new(); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index aa119819aaa26..82fa43f581fde 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -335,6 +335,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "proc-macro2", "psm", "pulldown-cmark", + "pulldown-cmark-escape", "punycode", "quote", "r-efi", From 61963fabdf2eaf9a68be970dfad7eb470a0fc0d5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:14:42 +0000 Subject: [PATCH 09/54] Avoid an ICE reachable through const eval shenanigans --- .../rustc_hir_typeck/src/method/confirm.rs | 9 ++-- .../arbitrary-self-from-method-substs-ice.rs | 29 ++++++++++++ ...bitrary-self-from-method-substs-ice.stderr | 46 +++++++++++++++++++ ...ary-self-from-method-substs.default.stderr | 1 - 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 tests/ui/self/arbitrary-self-from-method-substs-ice.rs create mode 100644 tests/ui/self/arbitrary-self-from-method-substs-ice.stderr diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 120e3239d1f1b..02844bcadac6e 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -510,9 +510,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { .report_mismatched_types(&cause, method_self_ty, self_ty, terr) .emit(); } else { - error!("{self_ty} was a subtype of {method_self_ty} but now is not?"); - // This must already have errored elsewhere. - self.dcx().has_errors().unwrap(); + // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions + // may run before wfcheck if the function is used in const eval. + self.dcx().span_delayed_bug( + cause.span(), + format!("{self_ty} was a subtype of {method_self_ty} but now is not?"), + ); } } } diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs new file mode 100644 index 0000000000000..8bf9f97e0b91d --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs @@ -0,0 +1,29 @@ +//! The same as the non-ICE test, but const eval will run typeck of +//! `get` before running wfcheck (as that may in itself trigger const +//! eval again, and thus cause bogus cycles). This used to ICE because +//! we asserted that an error had already been emitted. + +use std::ops::Deref; + +struct Foo(u32); +impl Foo { + const fn get>(self: R) -> u32 { + //~^ ERROR: `R` cannot be used as the type of `self` + //~| ERROR destructor of `R` cannot be evaluated at compile-time + self.0 + //~^ ERROR cannot borrow here, since the borrowed element may contain interior mutability + //~| ERROR cannot call non-const fn `::deref` in constant function + } +} + +const FOO: () = { + let foo = Foo(1); + foo.get::<&Foo>(); +}; + +const BAR: [(); { + FOO; + 0 +}] = []; + +fn main() {} diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr new file mode 100644 index 0000000000000..9e3851f9a6e72 --- /dev/null +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -0,0 +1,46 @@ +error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability + --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 + | +LL | self.0 + | ^^^^ + | + = note: see issue #80384 for more information + = help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0015]: cannot call non-const fn `::deref` in constant functions + --> $DIR/arbitrary-self-from-method-substs-ice.rs:13:9 + | +LL | self.0 + | ^^^^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + | +LL + #![feature(const_trait_impl)] + | + +error[E0493]: destructor of `R` cannot be evaluated at compile-time + --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:43 + | +LL | const fn get>(self: R) -> u32 { + | ^^^^ the destructor for this type cannot be evaluated in constant functions +... +LL | } + | - value is dropped here + +error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature + --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 + | +LL | const fn get>(self: R) -> u32 { + | ^ + | + = note: see issue #44874 for more information + = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0015, E0493, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr index 6fff086a89c2e..4cc69666b8876 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr @@ -9,7 +9,6 @@ LL | fn get>(self: R) -> u32 { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) - ERROR rustc_hir_typeck::method::confirm Foo was a subtype of &Foo but now is not? error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. From 9d5da39b3a4d3155dca12db9eb7ea6be6234e8a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:26:27 +0000 Subject: [PATCH 10/54] Revert some ICE avoiding logic that is not necessary anymore --- compiler/rustc_hir_typeck/src/writeback.rs | 25 +++------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index aea0114167eb9..ceb7480686d90 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -219,28 +219,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) { 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() { - // When encountering `return [0][0]` outside of a `fn` body we can encounter a base - // that isn't in the type table. We assume more relevant errors have already been - // emitted. (#64638) - assert!(self.tcx().dcx().has_errors().is_some(), "bad base: `{base:?}`"); - } - if let Some(base_ty) = base_ty - && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() - { - let index_ty = - self.typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| { - // When encountering `return [0][0]` outside of a `fn` body we would attempt - // to access an nonexistent index. We assume that more relevant errors will - // already have been emitted, so we only gate on this with an ICE if no - // error has been emitted. (#64638) - Ty::new_error_with_message( - self.fcx.tcx, - e.span, - format!("bad index {index:?} for base: `{base:?}`"), - ) - }); + let base_ty = self.typeck_results.expr_ty_adjusted(base); + if let ty::Ref(_, base_ty_inner, _) = *base_ty.kind() { + let index_ty = self.typeck_results.expr_ty_adjusted(index); if self.is_builtin_index(e, base_ty_inner, index_ty) { // Remove the method call record self.typeck_results.type_dependent_defs_mut().remove(e.hir_id); From a5d37238a1171ddcf0bbf37f5900bcb442678ffd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:31:41 +0000 Subject: [PATCH 11/54] Prefer item-local tainting checks over global error count checks --- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2fbc8a3f146a1..f3aece4e1d8aa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -708,7 +708,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // else an error would have been flagged by the // `loops` pass for using break with an expression // where you are not supposed to. - assert!(expr_opt.is_none() || self.dcx().has_errors().is_some()); + assert!(expr_opt.is_none() || self.tainted_by_errors().is_some()); } // If we encountered a `break`, then (no surprise) it may be possible to break from the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 430e12ff7b87b..ba7719bbb4e6d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1652,7 +1652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); - // Hide the outer diverging and `has_errors` flags. + // Hide the outer diverging flags. let old_diverges = self.diverges.replace(Diverges::Maybe); match stmt.kind { From 814bfe9335fd7c941169e0ef15ae2cffeacc78eb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 1 Jul 2024 10:35:16 +0000 Subject: [PATCH 12/54] This check should now be unreachable --- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 9a353bfe49d0e..c8ab0429ffc70 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,9 +734,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - if self.cx.tcx().dcx().has_errors().is_none() { - span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); - } + span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); } } From bd2ff518cefe1dc9e1dcd328319eead618eed67a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 18:44:11 +0000 Subject: [PATCH 13/54] Move codegen_and_build_linker from Queries to Linker --- compiler/rustc_driver_impl/src/lib.rs | 6 ++- compiler/rustc_interface/src/lib.rs | 2 +- compiler/rustc_interface/src/queries.rs | 59 +++++++++++++------------ tests/ui-fulldeps/run-compiler-twice.rs | 7 ++- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 3780e575b9352..ad2acb03b3f67 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -30,7 +30,7 @@ use rustc_errors::{ }; use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, get_codegen_backend}; -use rustc_interface::{interface, passes, Queries}; +use rustc_interface::{interface, passes, Linker, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; @@ -447,7 +447,9 @@ fn run_compiler( return early_exit(); } - Ok(Some(queries.codegen_and_build_linker()?)) + queries.global_ctxt()?.enter(|tcx| { + Ok(Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)?)) + }) })?; // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 38f64ebb04e7b..e37b30749ab30 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -16,7 +16,7 @@ pub mod util; pub use callbacks::setup_callbacks; pub use interface::{run_compiler, Config}; pub use passes::DEFAULT_QUERY_PROVIDERS; -pub use queries::Queries; +pub use queries::{Linker, Queries}; #[cfg(test)] mod tests; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 5f00d7a76b29b..e78576c8e4301 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -116,35 +116,6 @@ impl<'tcx> Queries<'tcx> { ) }) } - - pub fn codegen_and_build_linker(&'tcx self) -> Result { - self.global_ctxt()?.enter(|tcx| { - let ongoing_codegen = passes::start_codegen(&*self.compiler.codegen_backend, tcx)?; - - // This must run after monomorphization so that all generic types - // have been instantiated. - if tcx.sess.opts.unstable_opts.print_type_sizes { - tcx.sess.code_stats.print_type_sizes(); - } - - if tcx.sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = tcx.crate_name(LOCAL_CRATE); - - tcx.sess.code_stats.print_vtable_sizes(crate_name); - } - - Ok(Linker { - dep_graph: tcx.dep_graph.clone(), - output_filenames: tcx.output_filenames(()).clone(), - crate_hash: if tcx.needs_crate_hash() { - Some(tcx.crate_hash(LOCAL_CRATE)) - } else { - None - }, - ongoing_codegen, - }) - }) - } } pub struct Linker { @@ -156,6 +127,36 @@ pub struct Linker { } impl Linker { + pub fn codegen_and_build_linker( + tcx: TyCtxt<'_>, + codegen_backend: &dyn CodegenBackend, + ) -> Result { + let ongoing_codegen = passes::start_codegen(codegen_backend, tcx)?; + + // This must run after monomorphization so that all generic types + // have been instantiated. + if tcx.sess.opts.unstable_opts.print_type_sizes { + tcx.sess.code_stats.print_type_sizes(); + } + + if tcx.sess.opts.unstable_opts.print_vtable_sizes { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + tcx.sess.code_stats.print_vtable_sizes(crate_name); + } + + Ok(Linker { + dep_graph: tcx.dep_graph.clone(), + output_filenames: tcx.output_filenames(()).clone(), + crate_hash: if tcx.needs_crate_hash() { + Some(tcx.crate_hash(LOCAL_CRATE)) + } else { + None + }, + ongoing_codegen, + }) + } + pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) -> Result<()> { let (codegen_results, work_products) = codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames); diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index 02748626723d9..720fc42cc5700 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -17,6 +17,7 @@ extern crate rustc_span; use std::path::{Path, PathBuf}; +use rustc_interface::Linker; use rustc_interface::interface; use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes}; use rustc_span::FileName; @@ -78,8 +79,10 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path interface::run_compiler(config, |compiler| { let linker = compiler.enter(|queries| { - queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; - queries.codegen_and_build_linker() + queries.global_ctxt()?.enter(|tcx| { + tcx.analysis(())?; + Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend) + }) }); linker.unwrap().link(&compiler.sess, &*compiler.codegen_backend).unwrap(); }); From ec2d1b0ed2f62d0d1da2ce1d5fbffc2eea4ff7b8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 19:29:25 +0000 Subject: [PATCH 14/54] Minor change --- compiler/rustc_interface/src/queries.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index e78576c8e4301..370c06c22a7de 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -210,7 +210,7 @@ impl Compiler { F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, { // Must declare `_timer` first so that it is dropped after `queries`. - let mut _timer = None; + let _timer; let queries = Queries::new(self); let ret = f(&queries); @@ -233,7 +233,7 @@ impl Compiler { // The timer's lifetime spans the dropping of `queries`, which contains // the global context. - _timer = Some(self.sess.timer("free_global_ctxt")); + _timer = self.sess.timer("free_global_ctxt"); if let Err((path, error)) = queries.finish() { self.sess.dcx().emit_fatal(errors::FailedWritingFile { path: &path, error }); } From f27645927c15c8f643242101ced25492bacf0cce Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 30 Jun 2024 19:40:54 +0000 Subject: [PATCH 15/54] Inline Query::default() --- compiler/rustc_interface/src/queries.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 370c06c22a7de..821e8ee7ba589 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -65,12 +65,6 @@ impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> { } } -impl Default for Query { - fn default() -> Self { - Query { result: RefCell::new(None) } - } -} - pub struct Queries<'tcx> { compiler: &'tcx Compiler, gcx_cell: OnceLock>, @@ -90,8 +84,8 @@ impl<'tcx> Queries<'tcx> { gcx_cell: OnceLock::new(), arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), - parse: Default::default(), - gcx: Default::default(), + parse: Query { result: RefCell::new(None) }, + gcx: Query { result: RefCell::new(None) }, } } From 294c3dda881ae65d528ee0380b7628deaf33ae96 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 11:24:36 -0700 Subject: [PATCH 16/54] rustdoc: add usable lint for pulldown-cmark-0.11 parsing changes --- Cargo.lock | 12 ++ src/librustdoc/Cargo.toml | 1 + src/librustdoc/lint.rs | 9 ++ src/librustdoc/passes/lint.rs | 2 + .../passes/lint/unportable_markdown.rs | 152 ++++++++++++++++++ tests/rustdoc-ui/unportable-markdown.rs | 63 ++++++++ tests/rustdoc-ui/unportable-markdown.stderr | 39 +++++ 7 files changed, 278 insertions(+) create mode 100644 src/librustdoc/passes/lint/unportable_markdown.rs create mode 100644 tests/rustdoc-ui/unportable-markdown.rs create mode 100644 tests/rustdoc-ui/unportable-markdown.stderr diff --git a/Cargo.lock b/Cargo.lock index 3af90a252aea7..96cef9070842e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3121,6 +3121,17 @@ dependencies = [ "cc", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.5.0", + "memchr", + "unicase", +] + [[package]] name = "pulldown-cmark" version = "0.10.3" @@ -4890,6 +4901,7 @@ dependencies = [ "indexmap", "itertools", "minifier", + "pulldown-cmark 0.9.6", "regex", "rustdoc-json-types", "serde", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 31222f213d800..51fb126cb3407 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -13,6 +13,7 @@ base64 = "0.21.7" itertools = "0.12" indexmap = "2" minifier = "0.3.0" +pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde_json = "1.0" diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index dd2bb47e5926b..8eaca70eaff48 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -196,6 +196,14 @@ declare_rustdoc_lint! { "detects redundant explicit links in doc comments" } +declare_rustdoc_lint! { + /// This compatibility lint checks for Markdown syntax that works in the old engine but not + /// the new one. + UNPORTABLE_MARKDOWN, + Warn, + "detects markdown that is interpreted differently in different parser" +} + pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -209,6 +217,7 @@ pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { MISSING_CRATE_LEVEL_DOCS, UNESCAPED_BACKTICKS, REDUNDANT_EXPLICIT_LINKS, + UNPORTABLE_MARKDOWN, ] }); diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index c6d5b7bd346d4..bc804a340bf2c 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -6,6 +6,7 @@ mod check_code_block_syntax; mod html_tags; mod redundant_explicit_links; mod unescaped_backticks; +mod unportable_markdown; use super::Pass; use crate::clean::*; @@ -31,6 +32,7 @@ impl<'a, 'tcx> DocVisitor for Linter<'a, 'tcx> { html_tags::visit_item(self.cx, item); unescaped_backticks::visit_item(self.cx, item); redundant_explicit_links::visit_item(self.cx, item); + unportable_markdown::visit_item(self.cx, item); self.visit_item_recur(item) } diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs new file mode 100644 index 0000000000000..5f18537763441 --- /dev/null +++ b/src/librustdoc/passes/lint/unportable_markdown.rs @@ -0,0 +1,152 @@ +//! Detects specific markdown syntax that's different between pulldown-cmark +//! 0.9 and 0.11. +//! +//! This is a mitigation for old parser bugs that affected some +//! real crates' docs. The old parser claimed to comply with CommonMark, +//! but it did not. These warnings will eventually be removed, +//! though some of them may become Clippy lints. +//! +//! +//! +//! + +use crate::clean::Item; +use crate::core::DocContext; +use pulldown_cmark as cmarkn; +use pulldown_cmark_old as cmarko; +use rustc_lint_defs::Applicability; +use rustc_resolve::rustdoc::source_span_for_markdown_range; +use std::collections::{BTreeMap, BTreeSet}; + +pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { + let tcx = cx.tcx; + let Some(hir_id) = DocContext::as_local_hir_id(tcx, item.item_id) else { + // If non-local, no need to check anything. + return; + }; + + let dox = item.doc_value(); + if dox.is_empty() { + return; + } + + // P1: unintended strikethrough was fixed by requiring single-tildes to flank + // the same way underscores do, so nothing is done here + + // P2: block quotes without following space parsed wrong + // + // This is the set of starting points for block quotes with no space after + // the `>`. It is populated by the new parser, and if the old parser fails to + // clear it out, it'll produce a warning. + let mut spaceless_block_quotes = BTreeSet::new(); + + // P3: missing footnote references + // + // This is populated by listening for FootnoteReference from + // the new parser and old parser. + let mut missing_footnote_references = BTreeMap::new(); + let mut found_footnote_references = BTreeSet::new(); + + // populate problem cases from new parser + { + pub fn main_body_opts_new() -> cmarkn::Options { + cmarkn::Options::ENABLE_TABLES + | cmarkn::Options::ENABLE_FOOTNOTES + | cmarkn::Options::ENABLE_STRIKETHROUGH + | cmarkn::Options::ENABLE_TASKLISTS + | cmarkn::Options::ENABLE_SMART_PUNCTUATION + } + let mut parser_new = cmarkn::Parser::new_ext(&dox, main_body_opts_new()).into_offset_iter(); + while let Some((event, span)) = parser_new.next() { + if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event { + if !dox[span.clone()].starts_with("> ") { + spaceless_block_quotes.insert(span.start); + } + } + if let cmarkn::Event::FootnoteReference(_) = event { + found_footnote_references.insert(span.start + 1); + } + } + } + + // remove cases where they don't actually differ + { + pub fn main_body_opts_old() -> cmarko::Options { + cmarko::Options::ENABLE_TABLES + | cmarko::Options::ENABLE_FOOTNOTES + | cmarko::Options::ENABLE_STRIKETHROUGH + | cmarko::Options::ENABLE_TASKLISTS + | cmarko::Options::ENABLE_SMART_PUNCTUATION + } + let mut parser_old = cmarko::Parser::new_ext(&dox, main_body_opts_old()).into_offset_iter(); + while let Some((event, span)) = parser_old.next() { + if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event { + if !dox[span.clone()].starts_with("> ") { + spaceless_block_quotes.remove(&span.start); + } + } + if let cmarko::Event::FootnoteReference(_) = event { + if !found_footnote_references.contains(&(span.start + 1)) { + missing_footnote_references.insert(span.start + 1, span); + } + } + } + } + + for start in spaceless_block_quotes { + let (span, precise) = + source_span_for_markdown_range(tcx, &dox, &(start..start + 1), &item.attrs.doc_strings) + .map(|span| (span, true)) + .unwrap_or_else(|| (item.attr_span(tcx), false)); + + tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| { + lint.primary_message("unportable markdown"); + lint.help(format!("confusing block quote with no space after the `>` marker")); + if precise { + lint.span_suggestion( + span.shrink_to_hi(), + "if the quote is intended, add a space", + " ", + Applicability::MaybeIncorrect, + ); + lint.span_suggestion( + span.shrink_to_lo(), + "if it should not be a quote, escape it", + "\\", + Applicability::MaybeIncorrect, + ); + } + }); + } + for (_caret, span) in missing_footnote_references { + let (ref_span, precise) = + source_span_for_markdown_range(tcx, &dox, &span, &item.attrs.doc_strings) + .map(|span| (span, true)) + .unwrap_or_else(|| (item.attr_span(tcx), false)); + + tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| { + lint.primary_message("unportable markdown"); + if precise { + lint.span_suggestion( + ref_span.shrink_to_lo(), + "if it should not be a footnote, escape it", + "\\", + Applicability::MaybeIncorrect, + ); + } + if dox.as_bytes().get(span.end) == Some(&b'[') { + lint.help("confusing footnote reference and link"); + if precise { + lint.span_suggestion( + ref_span.shrink_to_hi(), + "if the footnote is intended, add a space", + " ", + Applicability::MaybeIncorrect, + ); + } else { + lint.help("there should be a space between the link and the footnote"); + } + } + }); + } +} diff --git a/tests/rustdoc-ui/unportable-markdown.rs b/tests/rustdoc-ui/unportable-markdown.rs new file mode 100644 index 0000000000000..8035e680f3cf4 --- /dev/null +++ b/tests/rustdoc-ui/unportable-markdown.rs @@ -0,0 +1,63 @@ +// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929 +// +// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes. +// +// This version of the lint is targeted at two especially-common cases where docs got broken. +// Other differences in parsing should not warn. +#![allow(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::unportable_markdown)] + +/// +/// +/// Test footnote [^foot]. +/// +/// [^foot]: This is nested within the footnote now, but didn't used to be. +/// +/// This is a multi-paragraph footnote. +pub struct GfmFootnotes; + +/// +/// +/// test [^foo][^bar] +//~^ ERROR unportable markdown +/// +/// [^foo]: test +/// [^bar]: test2 +pub struct FootnoteSmashedName; + +/// +/// +/// - _t +/// # test +/// t_ +pub struct NestingCornerCase; + +/// +/// +/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~ +pub struct Emphasis1; + +/// +/// +/// | +/// | +pub struct NotEnoughTable; + +/// +/// +/// foo +/// >bar +//~^ ERROR unportable markdown +pub struct BlockQuoteNoSpace; + +/// Negative test. +/// +/// foo +/// > bar +pub struct BlockQuoteSpace; + +/// Negative test. +/// +/// >bar +/// baz +pub struct BlockQuoteNoSpaceStart; diff --git a/tests/rustdoc-ui/unportable-markdown.stderr b/tests/rustdoc-ui/unportable-markdown.stderr new file mode 100644 index 0000000000000..b524aca25aef9 --- /dev/null +++ b/tests/rustdoc-ui/unportable-markdown.stderr @@ -0,0 +1,39 @@ +error: unportable markdown + --> $DIR/unportable-markdown.rs:21:10 + | +LL | /// test [^foo][^bar] + | ^^^^^^ + | + = help: confusing footnote reference and link +note: the lint level is defined here + --> $DIR/unportable-markdown.rs:8:9 + | +LL | #![deny(rustdoc::unportable_markdown)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if it should not be a footnote, escape it + | +LL | /// test \[^foo][^bar] + | + +help: if the footnote is intended, add a space + | +LL | /// test [^foo] [^bar] + | + + +error: unportable markdown + --> $DIR/unportable-markdown.rs:49:5 + | +LL | /// >bar + | ^ + | + = help: confusing block quote with no space after the `>` marker +help: if the quote is intended, add a space + | +LL | /// > bar + | + +help: if it should not be a quote, escape it + | +LL | /// \>bar + | + + +error: aborting due to 2 previous errors + From cc1b3ee7f1601499ec96dcdfcf6ac1ee40657e6b Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 29 Jun 2024 11:25:12 -0700 Subject: [PATCH 17/54] clippy: update to pulldown-cmark 0.11 --- src/tools/clippy/clippy_lints/src/doc/mod.rs | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 3d875e7ac2d3f..3e210fd153bf5 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -6,10 +6,10 @@ use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::Visitable; use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args}; use pulldown_cmark::Event::{ - Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text, + Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text, }; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; -use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options}; +use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_hir::intravisit::{self, Visitor}; @@ -659,7 +659,7 @@ fn check_doc<'a, Events: Iterator, Range { + Html(tag) | InlineHtml(tag) => { if tag.starts_with(", Range { + Start(BlockQuote(_)) => { blockquote_level += 1; containers.push(Container::Blockquote); }, - End(BlockQuote) => { + End(TagEnd::BlockQuote) => { blockquote_level -= 1; containers.pop(); }, @@ -699,15 +699,15 @@ fn check_doc<'a, Events: Iterator, Range { + End(TagEnd::CodeBlock) => { in_code = false; is_rust = false; ignore = false; }, - Start(Link(_, url, _)) => in_link = Some(url), - End(Link(..)) => in_link = None, - Start(Heading(_, _, _) | Paragraph | Item) => { - if let Start(Heading(_, _, _)) = event { + Start(Link { dest_url, .. }) => in_link = Some(dest_url), + End(TagEnd::Link) => in_link = None, + Start(Heading { .. } | Paragraph | Item) => { + if let Start(Heading { .. }) = event { in_heading = true; } if let Start(Item) = event { @@ -720,11 +720,11 @@ fn check_doc<'a, Events: Iterator, Range { - if let End(Heading(_, _, _)) = event { + End(TagEnd::Heading(_) | TagEnd::Paragraph | TagEnd::Item) => { + if let End(TagEnd::Heading(_)) = event { in_heading = false; } - if let End(Item) = event { + if let End(TagEnd::Item) = event { containers.pop(); } if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) { @@ -746,8 +746,8 @@ fn check_doc<'a, Events: Iterator, Range in_footnote_definition = true, - End(FootnoteDefinition(..)) => in_footnote_definition = false, - Start(_tag) | End(_tag) => (), // We don't care about other tags + End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, + Start(_) | End(_) => (), // We don't care about other tags SoftBreak | HardBreak => { if !containers.is_empty() && let Some((next_event, next_range)) = events.peek() @@ -765,7 +765,7 @@ fn check_doc<'a, Events: Iterator, Range (), + TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (), FootnoteReference(text) | Text(text) => { paragraph_range.end = range.end; ticks_unbalanced |= text.contains('`') && !in_code; From c8592da16a9e16535f3dfb9359066113f8656de0 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 30 Jun 2024 19:04:14 -0700 Subject: [PATCH 18/54] rustc_data_structures: fix wrong markdown syntax This didn't produce working footnote links. The unportable markdown lint warned about it. --- compiler/rustc_data_structures/src/sync.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 79ceb28abb518..058a675c40d7b 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -35,11 +35,11 @@ //! | | | | //! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | //! -//! [^1] `MTLock` is similar to `Lock`, but the serial version avoids the cost +//! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost //! of a `RefCell`. This is appropriate when interior mutability is not //! required. //! -//! [^2] `MTRef`, `MTLockRef` are type aliases. +//! [^2]: `MTRef`, `MTLockRef` are type aliases. pub use crate::marker::*; use std::collections::HashMap; From 1834f5a272d567a714f78c7f48c0d3ae4a6238bb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 26 Jun 2024 19:13:38 +0000 Subject: [PATCH 19/54] Swap encapsulation of DCP state. --- .../rustc_mir_dataflow/src/value_analysis.rs | 149 ++++++++++-------- 1 file changed, 81 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index bfbfff7e25944..0364c23bfcbe4 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -39,7 +39,7 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; @@ -336,14 +336,14 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper const NAME: &'static str = T::NAME; fn bottom_value(&self, _body: &Body<'tcx>) -> Self::Domain { - State(StateData::Unreachable) + State::Unreachable } fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. - assert!(matches!(state.0, StateData::Unreachable)); - let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); - *state = State(StateData::Reachable(values)); + assert!(matches!(state, State::Unreachable)); + let values = StateData::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); + *state = State::Reachable(values); for arg in body.args_iter() { state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); } @@ -415,27 +415,30 @@ rustc_index::newtype_index!( /// See [`State`]. #[derive(PartialEq, Eq, Debug)] -enum StateData { - Reachable(IndexVec), - Unreachable, +struct StateData { + map: IndexVec, +} + +impl StateData { + fn from_elem_n(elem: V, n: usize) -> StateData { + StateData { map: IndexVec::from_elem_n(elem, n) } + } } impl Clone for StateData { fn clone(&self) -> Self { - match self { - Self::Reachable(x) => Self::Reachable(x.clone()), - Self::Unreachable => Self::Unreachable, - } + StateData { map: self.map.clone() } } fn clone_from(&mut self, source: &Self) { - match (&mut *self, source) { - (Self::Reachable(x), Self::Reachable(y)) => { - // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. - x.raw.clone_from(&y.raw); - } - _ => *self = source.clone(), - } + // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. + self.map.raw.clone_from(&source.map.raw) + } +} + +impl JoinSemiLattice for StateData { + fn join(&mut self, other: &Self) -> bool { + self.map.join(&other.map) } } @@ -450,33 +453,43 @@ impl Clone for StateData { /// /// Flooding means assigning a value (by default `⊤`) to all tracked projections of a given place. #[derive(PartialEq, Eq, Debug)] -pub struct State(StateData); +pub enum State { + Unreachable, + Reachable(StateData), +} impl Clone for State { fn clone(&self) -> Self { - Self(self.0.clone()) + match self { + Self::Reachable(x) => Self::Reachable(x.clone()), + Self::Unreachable => Self::Unreachable, + } } fn clone_from(&mut self, source: &Self) { - self.0.clone_from(&source.0); + match (&mut *self, source) { + (Self::Reachable(x), Self::Reachable(y)) => { + x.clone_from(&y); + } + _ => *self = source.clone(), + } } } impl State { pub fn new(init: V, map: &Map) -> State { - let values = IndexVec::from_elem_n(init, map.value_count); - State(StateData::Reachable(values)) + State::Reachable(StateData::from_elem_n(init, map.value_count)) } pub fn all(&self, f: impl Fn(&V) -> bool) -> bool { - match self.0 { - StateData::Unreachable => true, - StateData::Reachable(ref values) => values.iter().all(f), + match self { + State::Unreachable => true, + State::Reachable(ref values) => values.map.iter().all(f), } } fn is_reachable(&self) -> bool { - matches!(&self.0, StateData::Reachable(_)) + matches!(self, State::Reachable(_)) } /// Assign `value` to all places that are contained in `place` or may alias one. @@ -519,9 +532,9 @@ impl State { map: &Map, value: V, ) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; map.for_each_aliasing_place(place, tail_elem, &mut |vi| { - values[vi] = value.clone(); + values.map[vi] = value.clone(); }); } @@ -541,9 +554,9 @@ impl State { /// /// The target place must have been flooded before calling this method. pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { - values[value_index] = value; + values.map[value_index] = value; } } @@ -555,14 +568,14 @@ impl State { /// /// The target place must have been flooded before calling this method. pub fn insert_place_idx(&mut self, target: PlaceIndex, source: PlaceIndex, map: &Map) { - let StateData::Reachable(values) = &mut self.0 else { return }; + let State::Reachable(values) = self else { return }; // If both places are tracked, we copy the value to the target. // If the target is tracked, but the source is not, we do nothing, as invalidation has // already been performed. if let Some(target_value) = map.places[target].value_index { if let Some(source_value) = map.places[source].value_index { - values[target_value] = values[source_value].clone(); + values.map[target_value] = values.map[source_value].clone(); } } for target_child in map.children(target) { @@ -616,11 +629,11 @@ impl State { /// Retrieve the value stored for a place index, or `None` if it is not tracked. pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { - match &self.0 { - StateData::Reachable(values) => { - map.places[place].value_index.map(|v| values[v].clone()) + match self { + State::Reachable(values) => { + map.places[place].value_index.map(|v| values.map[v].clone()) } - StateData::Unreachable => None, + State::Unreachable => None, } } @@ -631,10 +644,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -645,10 +658,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get_discr(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -659,10 +672,10 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP), + match self { + State::Reachable(_) => self.try_get_len(place, map).unwrap_or(V::TOP), // Because this is unreachable, we can return any value we want. - StateData::Unreachable => V::BOTTOM, + State::Unreachable => V::BOTTOM, } } @@ -673,11 +686,11 @@ impl State { where V: HasBottom + HasTop, { - match &self.0 { - StateData::Reachable(values) => { - map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP) + match self { + State::Reachable(values) => { + map.places[place].value_index.map(|v| values.map[v].clone()).unwrap_or(V::TOP) } - StateData::Unreachable => { + State::Unreachable => { // Because this is unreachable, we can return any value we want. V::BOTTOM } @@ -687,13 +700,13 @@ impl State { impl JoinSemiLattice for State { fn join(&mut self, other: &Self) -> bool { - match (&mut self.0, &other.0) { - (_, StateData::Unreachable) => false, - (StateData::Unreachable, _) => { + match (&mut *self, other) { + (_, State::Unreachable) => false, + (State::Unreachable, _) => { *self = other.clone(); true } - (StateData::Reachable(this), StateData::Reachable(other)) => this.join(other), + (State::Reachable(this), State::Reachable(ref other)) => this.join(other), } } } @@ -1194,9 +1207,9 @@ where T::Value: Debug, { fn fmt_with(&self, ctxt: &ValueAnalysisWrapper, f: &mut Formatter<'_>) -> std::fmt::Result { - match &self.0 { - StateData::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), - StateData::Unreachable => write!(f, "unreachable"), + match self { + State::Reachable(values) => debug_with_context(values, None, ctxt.0.map(), f), + State::Unreachable => write!(f, "unreachable"), } } @@ -1206,8 +1219,8 @@ where ctxt: &ValueAnalysisWrapper, f: &mut Formatter<'_>, ) -> std::fmt::Result { - match (&self.0, &old.0) { - (StateData::Reachable(this), StateData::Reachable(old)) => { + match (self, old) { + (State::Reachable(this), State::Reachable(old)) => { debug_with_context(this, Some(old), ctxt.0.map(), f) } _ => Ok(()), // Consider printing something here. @@ -1218,18 +1231,18 @@ where fn debug_with_context_rec( place: PlaceIndex, place_str: &str, - new: &IndexSlice, - old: Option<&IndexSlice>, + new: &StateData, + old: Option<&StateData>, map: &Map, f: &mut Formatter<'_>, ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { match old { - None => writeln!(f, "{}: {:?}", place_str, new[value])?, + None => writeln!(f, "{}: {:?}", place_str, new.map[value])?, Some(old) => { - if new[value] != old[value] { - writeln!(f, "\u{001f}-{}: {:?}", place_str, old[value])?; - writeln!(f, "\u{001f}+{}: {:?}", place_str, new[value])?; + if new.map[value] != old.map[value] { + writeln!(f, "\u{001f}-{}: {:?}", place_str, old.map[value])?; + writeln!(f, "\u{001f}+{}: {:?}", place_str, new.map[value])?; } } } @@ -1262,8 +1275,8 @@ fn debug_with_context_rec( } fn debug_with_context( - new: &IndexSlice, - old: Option<&IndexSlice>, + new: &StateData, + old: Option<&StateData>, map: &Map, f: &mut Formatter<'_>, ) -> std::fmt::Result { From 76244d4dbc768e15e429c1f66ec021884f369f5f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 26 Jun 2024 21:57:59 +0000 Subject: [PATCH 20/54] Make jump threading state sparse. --- .../src/framework/lattice.rs | 14 +++ .../rustc_mir_dataflow/src/value_analysis.rs | 91 ++++++++++++------- .../rustc_mir_transform/src/jump_threading.rs | 19 +++- 3 files changed, 86 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index 1c2b475a43c96..23738f7a4a538 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -76,6 +76,8 @@ pub trait MeetSemiLattice: Eq { /// A set that has a "bottom" element, which is less than or equal to any other element. pub trait HasBottom { const BOTTOM: Self; + + fn is_bottom(&self) -> bool; } /// A set that has a "top" element, which is greater than or equal to any other element. @@ -114,6 +116,10 @@ impl MeetSemiLattice for bool { impl HasBottom for bool { const BOTTOM: Self = false; + + fn is_bottom(&self) -> bool { + !self + } } impl HasTop for bool { @@ -267,6 +273,10 @@ impl MeetSemiLattice for FlatSet { impl HasBottom for FlatSet { const BOTTOM: Self = Self::Bottom; + + fn is_bottom(&self) -> bool { + matches!(self, Self::Bottom) + } } impl HasTop for FlatSet { @@ -291,6 +301,10 @@ impl MaybeReachable { impl HasBottom for MaybeReachable { const BOTTOM: Self = MaybeReachable::Unreachable; + + fn is_bottom(&self) -> bool { + matches!(self, Self::Unreachable) + } } impl HasTop for MaybeReachable { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 0364c23bfcbe4..7c1ff6fda53f7 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -36,7 +36,7 @@ use std::collections::VecDeque; use std::fmt::{Debug, Formatter}; use std::ops::Range; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; @@ -342,8 +342,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { // The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥. assert!(matches!(state, State::Unreachable)); - let values = StateData::from_elem_n(T::Value::BOTTOM, self.0.map().value_count); - *state = State::Reachable(values); + *state = State::new_reachable(); for arg in body.args_iter() { state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); } @@ -415,30 +414,54 @@ rustc_index::newtype_index!( /// See [`State`]. #[derive(PartialEq, Eq, Debug)] -struct StateData { - map: IndexVec, +pub struct StateData { + bottom: V, + /// This map only contains values that are not `⊥`. + map: FxHashMap, } -impl StateData { - fn from_elem_n(elem: V, n: usize) -> StateData { - StateData { map: IndexVec::from_elem_n(elem, n) } +impl StateData { + fn new() -> StateData { + StateData { bottom: V::BOTTOM, map: FxHashMap::default() } + } + + fn get(&self, idx: ValueIndex) -> &V { + self.map.get(&idx).unwrap_or(&self.bottom) + } + + fn insert(&mut self, idx: ValueIndex, elem: V) { + if elem.is_bottom() { + self.map.remove(&idx); + } else { + self.map.insert(idx, elem); + } } } impl Clone for StateData { fn clone(&self) -> Self { - StateData { map: self.map.clone() } + StateData { bottom: self.bottom.clone(), map: self.map.clone() } } fn clone_from(&mut self, source: &Self) { - // We go through `raw` here, because `IndexVec` currently has a naive `clone_from`. - self.map.raw.clone_from(&source.map.raw) + self.map.clone_from(&source.map) } } -impl JoinSemiLattice for StateData { +impl JoinSemiLattice for StateData { fn join(&mut self, other: &Self) -> bool { - self.map.join(&other.map) + let mut changed = false; + #[allow(rustc::potential_query_instability)] + for (i, v) in other.map.iter() { + match self.map.entry(*i) { + StdEntry::Vacant(e) => { + e.insert(v.clone()); + changed = true + } + StdEntry::Occupied(e) => changed |= e.into_mut().join(v), + } + } + changed } } @@ -476,15 +499,19 @@ impl Clone for State { } } -impl State { - pub fn new(init: V, map: &Map) -> State { - State::Reachable(StateData::from_elem_n(init, map.value_count)) +impl State { + pub fn new_reachable() -> State { + State::Reachable(StateData::new()) } - pub fn all(&self, f: impl Fn(&V) -> bool) -> bool { + pub fn all_bottom(&self) -> bool { match self { - State::Unreachable => true, - State::Reachable(ref values) => values.map.iter().all(f), + State::Unreachable => false, + State::Reachable(ref values) => + { + #[allow(rustc::potential_query_instability)] + values.map.values().all(V::is_bottom) + } } } @@ -533,9 +560,7 @@ impl State { value: V, ) { let State::Reachable(values) = self else { return }; - map.for_each_aliasing_place(place, tail_elem, &mut |vi| { - values.map[vi] = value.clone(); - }); + map.for_each_aliasing_place(place, tail_elem, &mut |vi| values.insert(vi, value.clone())); } /// Low-level method that assigns to a place. @@ -556,7 +581,7 @@ impl State { pub fn insert_value_idx(&mut self, target: PlaceIndex, value: V, map: &Map) { let State::Reachable(values) = self else { return }; if let Some(value_index) = map.places[target].value_index { - values.map[value_index] = value; + values.insert(value_index, value) } } @@ -575,7 +600,7 @@ impl State { // already been performed. if let Some(target_value) = map.places[target].value_index { if let Some(source_value) = map.places[source].value_index { - values.map[target_value] = values.map[source_value].clone(); + values.insert(target_value, values.get(source_value).clone()); } } for target_child in map.children(target) { @@ -631,7 +656,7 @@ impl State { pub fn try_get_idx(&self, place: PlaceIndex, map: &Map) -> Option { match self { State::Reachable(values) => { - map.places[place].value_index.map(|v| values.map[v].clone()) + map.places[place].value_index.map(|v| values.get(v).clone()) } State::Unreachable => None, } @@ -688,7 +713,7 @@ impl State { { match self { State::Reachable(values) => { - map.places[place].value_index.map(|v| values.map[v].clone()).unwrap_or(V::TOP) + map.places[place].value_index.map(|v| values.get(v).clone()).unwrap_or(V::TOP) } State::Unreachable => { // Because this is unreachable, we can return any value we want. @@ -698,7 +723,7 @@ impl State { } } -impl JoinSemiLattice for State { +impl JoinSemiLattice for State { fn join(&mut self, other: &Self) -> bool { match (&mut *self, other) { (_, State::Unreachable) => false, @@ -1228,7 +1253,7 @@ where } } -fn debug_with_context_rec( +fn debug_with_context_rec( place: PlaceIndex, place_str: &str, new: &StateData, @@ -1238,11 +1263,11 @@ fn debug_with_context_rec( ) -> std::fmt::Result { if let Some(value) = map.places[place].value_index { match old { - None => writeln!(f, "{}: {:?}", place_str, new.map[value])?, + None => writeln!(f, "{}: {:?}", place_str, new.get(value))?, Some(old) => { - if new.map[value] != old.map[value] { - writeln!(f, "\u{001f}-{}: {:?}", place_str, old.map[value])?; - writeln!(f, "\u{001f}+{}: {:?}", place_str, new.map[value])?; + if new.get(value) != old.get(value) { + writeln!(f, "\u{001f}-{}: {:?}", place_str, old.get(value))?; + writeln!(f, "\u{001f}+{}: {:?}", place_str, new.get(value))?; } } } @@ -1274,7 +1299,7 @@ fn debug_with_context_rec( Ok(()) } -fn debug_with_context( +fn debug_with_context( new: &StateData, old: Option<&StateData>, map: &Map, diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 27e506a920bce..85a61f95ca36f 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -47,6 +47,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ScalarInt, TyCtxt}; +use rustc_mir_dataflow::lattice::HasBottom; use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem}; use rustc_span::DUMMY_SP; use rustc_target::abi::{TagEncoding, Variants}; @@ -158,9 +159,17 @@ impl Condition { } } -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Debug)] struct ConditionSet<'a>(&'a [Condition]); +impl HasBottom for ConditionSet<'_> { + const BOTTOM: Self = ConditionSet(&[]); + + fn is_bottom(&self) -> bool { + self.0.is_empty() + } +} + impl<'a> ConditionSet<'a> { fn iter(self) -> impl Iterator + 'a { self.0.iter().copied() @@ -177,7 +186,7 @@ impl<'a> ConditionSet<'a> { impl<'tcx, 'a> TOFinder<'tcx, 'a> { fn is_empty(&self, state: &State>) -> bool { - state.all(|cs| cs.0.is_empty()) + state.all_bottom() } /// Recursion entry point to find threading opportunities. @@ -198,7 +207,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { debug!(?discr); let cost = CostChecker::new(self.tcx, self.param_env, None, self.body); - let mut state = State::new(ConditionSet::default(), self.map); + let mut state = State::new_reachable(); let conds = if let Some((value, then, else_)) = targets.as_static_if() { let value = ScalarInt::try_from_uint(value, discr_layout.size)?; @@ -255,7 +264,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // _1 = 5 // Whatever happens here, it won't change the result of a `SwitchInt`. // _1 = 6 if let Some((lhs, tail)) = self.mutated_statement(stmt) { - state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::default()); + state.flood_with_tail_elem(lhs.as_ref(), tail, self.map, ConditionSet::BOTTOM); } } @@ -609,7 +618,7 @@ impl<'tcx, 'a> TOFinder<'tcx, 'a> { // We can recurse through this terminator. let mut state = state(); if let Some(place_to_flood) = place_to_flood { - state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::default()); + state.flood_with(place_to_flood.as_ref(), self.map, ConditionSet::BOTTOM); } self.find_opportunity(bb, state, cost.clone(), depth + 1); } From 1680b791d57013ca2cf5839a279e3d4d826c336c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:33:46 +1000 Subject: [PATCH 21/54] Simplify `CfgEval`. It can contain an owned value instead of a reference. --- compiler/rustc_builtin_macros/src/cfg_eval.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 03aff6f96330e..884cebf1939e4 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -38,16 +38,14 @@ pub(crate) fn cfg_eval( lint_node_id: NodeId, ) -> Annotatable { let features = Some(features); - CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } } + CfgEval(StripUnconfigured { sess, features, config_tokens: true, lint_node_id }) .configure_annotatable(annotatable) // Since the item itself has already been configured by the `InvocationCollector`, // we know that fold result vector will contain exactly one element. .unwrap() } -struct CfgEval<'a, 'b> { - cfg: &'a mut StripUnconfigured<'b>, -} +struct CfgEval<'a>(StripUnconfigured<'a>); fn flat_map_annotatable( vis: &mut impl MutVisitor, @@ -125,9 +123,9 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { res.is_break() } -impl CfgEval<'_, '_> { +impl CfgEval<'_> { fn configure(&mut self, node: T) -> Option { - self.cfg.configure(node) + self.0.configure(node) } fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option { @@ -196,7 +194,7 @@ impl CfgEval<'_, '_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); + let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, @@ -212,16 +210,16 @@ impl CfgEval<'_, '_> { } } -impl MutVisitor for CfgEval<'_, '_> { +impl MutVisitor for CfgEval<'_> { #[instrument(level = "trace", skip(self))] fn visit_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr, false); + self.0.configure_expr(expr, false); mut_visit::noop_visit_expr(expr, self); } #[instrument(level = "trace", skip(self))] fn visit_method_receiver_expr(&mut self, expr: &mut P) { - self.cfg.configure_expr(expr, true); + self.0.configure_expr(expr, true); mut_visit::noop_visit_expr(expr, self); } From d6c0b8117e4ccccd83c4a6e70eee8b12c51d1a18 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:34:05 +1000 Subject: [PATCH 22/54] Fix a typo in a comment. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index b5480b6b7d210..4b1531c5ff3e4 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -340,7 +340,7 @@ impl<'a> Parser<'a> { // If we support tokens at all if let Some(target_tokens) = ret.tokens_mut() { if target_tokens.is_none() { - // Store se our newly captured tokens into the AST node + // Store our newly captured tokens into the AST node. *target_tokens = Some(tokens.clone()); } } From f852568fa601171f20f924a50478c33fd2661fba Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:42:46 +1000 Subject: [PATCH 23/54] Change `AttrTokenStream::to_tokenstream` to `to_token_trees`. I.e. change the return type from `TokenStream` to `Vec`. Most of the callsites require a `TokenStream`, but the recursive call used to create `target_tokens` requires a `Vec`. It's easy to convert a `Vec` to a `TokenStream` (just call `TokenStream::new`) but it's harder to convert a `TokenStream` to a `Vec` (either iterate/clone/collect, or use `Lrc::into_inner` if appropriate). So this commit changes the return value to simplify that `target_tokens` call site. --- compiler/rustc_ast/src/attr/mod.rs | 14 ++++++++------ compiler/rustc_ast/src/tokenstream.rs | 23 +++++++---------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 593c78df3cdb8..65f1b5dbaf5b7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -204,12 +204,14 @@ impl Attribute { pub fn tokens(&self) -> TokenStream { match &self.kind { - AttrKind::Normal(normal) => normal - .tokens - .as_ref() - .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) - .to_attr_token_stream() - .to_tokenstream(), + AttrKind::Normal(normal) => TokenStream::new( + normal + .tokens + .as_ref() + .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) + .to_attr_token_stream() + .to_token_trees(), + ), &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( token::DocComment(comment_kind, self.style, data), self.span, diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index b4ddbe20689e2..5b2d673316a52 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -180,14 +180,13 @@ impl AttrTokenStream { AttrTokenStream(Lrc::new(tokens)) } - /// Converts this `AttrTokenStream` to a plain `TokenStream`. + /// Converts this `AttrTokenStream` to a plain `Vec`. /// During conversion, `AttrTokenTree::Attributes` get 'flattened' /// back to a `TokenStream` of the form `outer_attr attr_target`. /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. - pub fn to_tokenstream(&self) -> TokenStream { - let trees: Vec<_> = self - .0 + pub fn to_token_trees(&self) -> Vec { + self.0 .iter() .flat_map(|tree| match &tree { AttrTokenTree::Token(inner, spacing) => { @@ -198,7 +197,7 @@ impl AttrTokenStream { *span, *spacing, *delim, - stream.to_tokenstream() + TokenStream::new(stream.to_token_trees()) ),] .into_iter() } @@ -208,14 +207,7 @@ impl AttrTokenStream { .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); - let mut target_tokens: Vec<_> = data - .tokens - .to_attr_token_stream() - .to_tokenstream() - .0 - .iter() - .cloned() - .collect(); + let mut target_tokens = data.tokens.to_attr_token_stream().to_token_trees(); if !inner_attrs.is_empty() { let mut found = false; // Check the last two trees (to account for a trailing semi) @@ -260,8 +252,7 @@ impl AttrTokenStream { flat.into_iter() } }) - .collect(); - TokenStream::new(trees) + .collect() } } @@ -461,7 +452,7 @@ impl TokenStream { AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) }; - attr_stream.to_tokenstream() + TokenStream::new(attr_stream.to_token_trees()) } pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { From 0cfd2473be4a5555018cfbca089a7ed1bfd16c53 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 10:49:12 +1000 Subject: [PATCH 24/54] Rename `TokenStream::new` argument. `tts` is a better name than `streams` for a `Vec`. --- compiler/rustc_ast/src/tokenstream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 5b2d673316a52..cabf18fd1530a 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -400,8 +400,8 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { - TokenStream(Lrc::new(streams)) + pub fn new(tts: Vec) -> TokenStream { + TokenStream(Lrc::new(tts)) } pub fn is_empty(&self) -> bool { From 7416c20cfd781de5608494d67975be94e8689c24 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 27 Jun 2024 11:15:38 +1000 Subject: [PATCH 25/54] Just `push` in `AttrTokenStream::to_token_trees`. Currently it uses a mixture of functional style (`flat_map`) and imperative style (`push`), which is a bit hard to read. This commit converts it to fully imperative, which is more concise and avoids the need for `smallvec`. --- compiler/rustc_ast/src/tokenstream.rs | 28 ++++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index cabf18fd1530a..655c18e45597a 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -23,7 +23,6 @@ use rustc_data_structures::sync::{self, Lrc}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::{cmp, fmt, iter}; @@ -186,20 +185,19 @@ impl AttrTokenStream { /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. pub fn to_token_trees(&self) -> Vec { - self.0 - .iter() - .flat_map(|tree| match &tree { + let mut res = Vec::with_capacity(self.0.len()); + for tree in self.0.iter() { + match tree { AttrTokenTree::Token(inner, spacing) => { - smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter() + res.push(TokenTree::Token(inner.clone(), *spacing)); } AttrTokenTree::Delimited(span, spacing, delim, stream) => { - smallvec![TokenTree::Delimited( + res.push(TokenTree::Delimited( *span, *spacing, *delim, - TokenStream::new(stream.to_token_trees()) - ),] - .into_iter() + TokenStream::new(stream.to_token_trees()), + )) } AttrTokenTree::Attributes(data) => { let idx = data @@ -243,16 +241,14 @@ impl AttrTokenStream { "Failed to find trailing delimited group in: {target_tokens:?}" ); } - let mut flat: SmallVec<[_; 1]> = - SmallVec::with_capacity(target_tokens.len() + outer_attrs.len()); for attr in outer_attrs { - flat.extend(attr.tokens().0.iter().cloned()); + res.extend(attr.tokens().0.iter().cloned()); } - flat.extend(target_tokens); - flat.into_iter() + res.extend(target_tokens); } - }) - .collect() + } + } + res } } From 36c30a968b60a2926a0f600feb78eaba618d8d9a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 14:32:47 +1000 Subject: [PATCH 26/54] Fix comment. Both the indenting, and the missing `)`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 4b1531c5ff3e4..a5aaa9f052208 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -233,9 +233,9 @@ impl<'a> Parser<'a> { // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`) // so there's nothing for us to do. // 2. Our target already has tokens set (e.g. we've parsed something - // like `#[my_attr] $item`. The actual parsing code takes care of prepending - // any attributes to the nonterminal, so we don't need to modify the - // already captured tokens. + // like `#[my_attr] $item`). The actual parsing code takes care of + // prepending any attributes to the nonterminal, so we don't need to + // modify the already captured tokens. // Note that this check is independent of `force_collect`- if we already // have tokens, or can't even store them, then there's never a need to // force collection of new tokens. From 2342770f49dcc7e98069efb2db3620d4803c7698 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:50:06 +1000 Subject: [PATCH 27/54] Flip an if/else in `AttrTokenStream::to_attr_token_stream`. To put the simple case first. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index a5aaa9f052208..244a4f26fba85 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -112,7 +112,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { })) .take(self.num_calls); - if !self.replace_ranges.is_empty() { + if self.replace_ranges.is_empty() { + make_token_stream(tokens, self.break_last_token) + } else { let mut tokens: Vec<_> = tokens.collect(); let mut replace_ranges = self.replace_ranges.to_vec(); replace_ranges.sort_by_key(|(range, _)| range.start); @@ -165,8 +167,6 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { ); } make_token_stream(tokens.into_iter(), self.break_last_token) - } else { - make_token_stream(tokens, self.break_last_token) } } } From 8b5a7eb7f4840dcc27e1dcf4a0e102a417ad988f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:12:22 +1000 Subject: [PATCH 28/54] Move things around in `collect_tokens_trailing_token`. So that the `capturing` state is adjusted immediately before and after the call to `f`. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 244a4f26fba85..7c22cac350b02 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -218,16 +218,16 @@ impl<'a> Parser<'a> { let start_token = (self.token.clone(), self.token_spacing); let cursor_snapshot = self.token_cursor.clone(); let start_pos = self.num_bump_calls; - let has_outer_attrs = !attrs.attrs.is_empty(); - let prev_capturing = std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let replace_ranges_start = self.capture_state.replace_ranges.len(); - let ret = f(self, attrs.attrs); - - self.capture_state.capturing = prev_capturing; - - let (mut ret, trailing) = ret?; + let (mut ret, trailing) = { + let prev_capturing = + std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); + let ret_and_trailing = f(self, attrs.attrs); + self.capture_state.capturing = prev_capturing; + ret_and_trailing? + }; // When we're not in `capture-cfg` mode, then bail out early if: // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`) From f5b28968db07c96d1e2fe239d380fe5a418e85c5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Jul 2024 16:21:47 +1000 Subject: [PATCH 29/54] Move more things around in `collect_tokens_trailing_token`. To make things a little clearer, and to avoid some `mut` variables. --- .../rustc_parse/src/parser/attr_wrapper.rs | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 7c22cac350b02..10feccd21e286 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -276,37 +276,32 @@ impl<'a> Parser<'a> { let replace_ranges_end = self.capture_state.replace_ranges.len(); - let mut end_pos = self.num_bump_calls; - - let mut captured_trailing = false; - // Capture a trailing token if requested by the callback 'f' - match trailing { - TrailingToken::None => {} + let captured_trailing = match trailing { + TrailingToken::None => false, TrailingToken::Gt => { assert_eq!(self.token.kind, token::Gt); + false } TrailingToken::Semi => { assert_eq!(self.token.kind, token::Semi); - end_pos += 1; - captured_trailing = true; + true } - TrailingToken::MaybeComma => { - if self.token.kind == token::Comma { - end_pos += 1; - captured_trailing = true; - } - } - } + TrailingToken::MaybeComma => self.token.kind == token::Comma, + }; - // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), - // then extend the range of captured tokens to include it, since the parser - // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted - // into an `AttrTokenStream`, we will create the proper token. - if self.break_last_token { - assert!(!captured_trailing, "Cannot set break_last_token and have trailing token"); - end_pos += 1; - } + assert!( + !(self.break_last_token && captured_trailing), + "Cannot set break_last_token and have trailing token" + ); + + let end_pos = self.num_bump_calls + + captured_trailing as usize + // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then + // extend the range of captured tokens to include it, since the parser was not actually + // bumped past it. When the `LazyAttrTokenStream` gets converted into an + // `AttrTokenStream`, we will create the proper token. + + self.break_last_token as usize; let num_calls = end_pos - start_pos; From 3d750e270279d2d8689aee3ee5cdbf60faec42bd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 16:31:24 +1000 Subject: [PATCH 30/54] Shrink parser positions from `usize` to `u32`. The number of source code bytes can't exceed a `u32`'s range, so a token position also can't. This reduces the size of `Parser` and `LazyAttrTokenStreamImpl` by eight bytes each. --- compiler/rustc_expand/src/mbe/diagnostics.rs | 12 +++++------ compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 4 ++-- .../rustc_parse/src/parser/attr_wrapper.rs | 21 ++++++++----------- compiler/rustc_parse/src/parser/mod.rs | 6 +++--- 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index bf475c1dc96ff..2df8b8f00f862 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -120,21 +120,21 @@ struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { struct BestFailure { token: Token, - position_in_tokenstream: usize, + position_in_tokenstream: u32, msg: &'static str, remaining_matcher: MatcherLoc, } impl BestFailure { - fn is_better_position(&self, position: usize) -> bool { + fn is_better_position(&self, position: u32) -> bool { position > self.position_in_tokenstream } } impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { - type Failure = (Token, usize, &'static str); + type Failure = (Token, u32, &'static str); - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure { + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { (tok, position, msg) } @@ -211,9 +211,9 @@ impl<'matcher> FailureForwarder<'matcher> { } impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> { - type Failure = (Token, usize, &'static str); + type Failure = (Token, u32, &'static str); - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure { + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure { (tok, position, msg) } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 2fbd09fd9ae20..99a9d4f8912cd 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -452,7 +452,7 @@ impl TtParser { &mut self, matcher: &'matcher [MatcherLoc], token: &Token, - approx_position: usize, + approx_position: u32, track: &mut T, ) -> Option> { // Matcher positions that would be valid if the macro invocation was over now. Only diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e43ba7c3a5a8f..88ec3d8366429 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -153,7 +153,7 @@ pub(super) trait Tracker<'matcher> { /// Arm failed to match. If the token is `token::Eof`, it indicates an unexpected /// end of macro invocation. Otherwise, it indicates that no rules expected the given token. /// The usize is the approximate position of the token in the input token stream. - fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure; + fn build_failure(tok: Token, position: u32, msg: &'static str) -> Self::Failure; /// This is called before trying to match next MatcherLoc on the current token. fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) {} @@ -182,7 +182,7 @@ pub(super) struct NoopTracker; impl<'matcher> Tracker<'matcher> for NoopTracker { type Failure = (); - fn build_failure(_tok: Token, _position: usize, _msg: &'static str) -> Self::Failure {} + fn build_failure(_tok: Token, _position: u32, _msg: &'static str) -> Self::Failure {} fn description() -> &'static str { "none" diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 10feccd21e286..d0d01cec816fb 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -29,15 +29,15 @@ pub struct AttrWrapper { // The start of the outer attributes in the token cursor. // This allows us to create a `ReplaceRange` for the entire attribute // target, including outer attributes. - start_pos: usize, + start_pos: u32, } impl AttrWrapper { - pub(super) fn new(attrs: AttrVec, start_pos: usize) -> AttrWrapper { + pub(super) fn new(attrs: AttrVec, start_pos: u32) -> AttrWrapper { AttrWrapper { attrs, start_pos } } pub fn empty() -> AttrWrapper { - AttrWrapper { attrs: AttrVec::new(), start_pos: usize::MAX } + AttrWrapper { attrs: AttrVec::new(), start_pos: u32::MAX } } pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec { @@ -91,7 +91,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, - num_calls: usize, + num_calls: u32, break_last_token: bool, replace_ranges: Box<[ReplaceRange]>, } @@ -110,7 +110,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { let token = cursor_snapshot.next(); (FlatToken::Token(token.0), token.1) })) - .take(self.num_calls); + .take(self.num_calls as usize); if self.replace_ranges.is_empty() { make_token_stream(tokens, self.break_last_token) @@ -296,12 +296,12 @@ impl<'a> Parser<'a> { ); let end_pos = self.num_bump_calls - + captured_trailing as usize + + captured_trailing as u32 // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then // extend the range of captured tokens to include it, since the parser was not actually // bumped past it. When the `LazyAttrTokenStream` gets converted into an // `AttrTokenStream`, we will create the proper token. - + self.break_last_token as usize; + + self.break_last_token as u32; let num_calls = end_pos - start_pos; @@ -313,14 +313,11 @@ impl<'a> Parser<'a> { // Grab any replace ranges that occur *inside* the current AST node. // We will perform the actual replacement when we convert the `LazyAttrTokenStream` // to an `AttrTokenStream`. - let start_calls: u32 = start_pos.try_into().unwrap(); self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] .iter() .cloned() .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, tokens)| { - ((range.start - start_calls)..(range.end - start_calls), tokens) - }) + .map(|(range, tokens)| ((range.start - start_pos)..(range.end - start_pos), tokens)) .collect() }; @@ -459,6 +456,6 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(AttrWrapper, 16); - static_assert_size!(LazyAttrTokenStreamImpl, 104); + static_assert_size!(LazyAttrTokenStreamImpl, 96); // tidy-alphabetical-end } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index cfd0a72c056d5..5f16a3e1f3784 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -153,7 +153,7 @@ pub struct Parser<'a> { expected_tokens: Vec, token_cursor: TokenCursor, // The number of calls to `bump`, i.e. the position in the token stream. - num_bump_calls: usize, + num_bump_calls: u32, // During parsing we may sometimes need to 'unglue' a glued token into two // component tokens (e.g. '>>' into '>' and '>), so the parser can consume // them one at a time. This process bypasses the normal capturing mechanism @@ -192,7 +192,7 @@ pub struct Parser<'a> { // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(Parser<'_>, 264); +rustc_data_structures::static_assert_size!(Parser<'_>, 256); /// Stores span information about a closure. #[derive(Clone, Debug)] @@ -1572,7 +1572,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn approx_token_stream_pos(&self) -> usize { + pub fn approx_token_stream_pos(&self) -> u32 { self.num_bump_calls } } From 6f6015679fb0153bd35d1b56df2456bb6146a9af Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 17:38:43 +1000 Subject: [PATCH 31/54] Rename `make_token_stream`. And update the comment. Clearly the return type of this function was changed at some point in the past, but its name and comment weren't updated to match. --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index d0d01cec816fb..3afd178cc2b4e 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -113,7 +113,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { .take(self.num_calls as usize); if self.replace_ranges.is_empty() { - make_token_stream(tokens, self.break_last_token) + make_attr_token_stream(tokens, self.break_last_token) } else { let mut tokens: Vec<_> = tokens.collect(); let mut replace_ranges = self.replace_ranges.to_vec(); @@ -166,7 +166,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { new_tokens.into_iter().chain(filler), ); } - make_token_stream(tokens.into_iter(), self.break_last_token) + make_attr_token_stream(tokens.into_iter(), self.break_last_token) } } } @@ -374,10 +374,10 @@ impl<'a> Parser<'a> { } } -/// Converts a flattened iterator of tokens (including open and close delimiter tokens) -/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair -/// of open and close delims. -fn make_token_stream( +/// Converts a flattened iterator of tokens (including open and close delimiter tokens) into an +/// `AttrTokenStream`, creating an `AttrTokenTree::Delimited` for each matching pair of open and +/// close delims. +fn make_attr_token_stream( mut iter: impl Iterator, break_last_token: bool, ) -> AttrTokenStream { From 565ddfb48ca2a3b24236c2b393ec14eb86d64a7a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 6 Jun 2024 19:57:36 +0300 Subject: [PATCH 32/54] linker: Link dylib crates by path --- compiler/rustc_codegen_ssa/src/back/link.rs | 42 ++---- compiler/rustc_codegen_ssa/src/back/linker.rs | 137 +++++++++++------- tests/run-make/dylib-soname/foo.rs | 1 + tests/run-make/dylib-soname/rmake.rs | 19 +++ 4 files changed, 114 insertions(+), 85 deletions(-) create mode 100644 tests/run-make/dylib-soname/foo.rs create mode 100644 tests/run-make/dylib-soname/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index da4fa41e2aafc..1f627353d54e1 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2817,6 +2817,15 @@ fn rehome_sysroot_lib_dir(sess: &Session, lib_dir: &Path) -> PathBuf { } } +fn rehome_lib_path(sess: &Session, path: &Path) -> PathBuf { + if let Some(dir) = path.parent() { + let file_name = path.file_name().expect("library path has no file name component"); + rehome_sysroot_lib_dir(sess, dir).join(file_name) + } else { + fix_windows_verbatim_for_gcc(path) + } +} + // Adds the static "rlib" versions of all crates to the command line. // There's a bit of magic which happens here specifically related to LTO, // namely that we remove upstream object files. @@ -2847,15 +2856,8 @@ fn add_static_crate( let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; - let mut link_upstream = |path: &Path| { - let rlib_path = if let Some(dir) = path.parent() { - let file_name = path.file_name().expect("rlib path has no file name path component"); - rehome_sysroot_lib_dir(sess, dir).join(file_name) - } else { - fix_windows_verbatim_for_gcc(path) - }; - cmd.link_staticlib_by_path(&rlib_path, false); - }; + let mut link_upstream = + |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false); if !are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum) @@ -2919,27 +2921,7 @@ fn add_static_crate( // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // Just need to tell the linker about where the library lives and - // what its name is - let parent = cratepath.parent(); - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() { - return; - } - if let Some(dir) = parent { - cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); - } - // "

    /name.dll -> name.dll" on windows-msvc - // "/name.dll -> name" on windows-gnu - // "/libname. -> name" elsewhere - let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; - let stem = stem.unwrap().to_str().unwrap(); - // Convert library file-stem into a cc -l argument. - let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_dylib_by_name(&stem[prefix..], false, true); + cmd.link_dylib_by_path(&rehome_lib_path(sess, cratepath), true); } fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 0f75ece9729cd..2bd5dfdce83ee 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -268,7 +268,12 @@ pub trait Linker { false } fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } + fn link_dylib_by_path(&mut self, _path: &Path, _as_needed: bool) { + bug!("dylib linked with unsupported linker") + } fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("framework linked with unsupported linker") } @@ -403,28 +408,53 @@ impl<'a> GccLinker<'a> { } } else { self.link_or_cc_arg("-shared"); - if self.sess.target.is_like_windows { - // The output filename already contains `dll_suffix` so - // the resulting import library will have a name in the - // form of libfoo.dll.a - let implib_name = - out_filename.file_name().and_then(|file| file.to_str()).map(|file| { - format!( - "{}{}{}", - self.sess.target.staticlib_prefix, - file, - self.sess.target.staticlib_suffix - ) - }); - if let Some(implib_name) = implib_name { - let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); - if let Some(implib) = implib { - self.link_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); - } + if let Some(name) = out_filename.file_name() { + if self.sess.target.is_like_windows { + // The output filename already contains `dll_suffix` so + // the resulting import library will have a name in the + // form of libfoo.dll.a + let mut implib_name = OsString::from(&*self.sess.target.staticlib_prefix); + implib_name.push(name); + implib_name.push(&*self.sess.target.staticlib_suffix); + let mut out_implib = OsString::from("--out-implib="); + out_implib.push(out_filename.with_file_name(implib_name)); + self.link_arg(out_implib); + } else { + // When dylibs are linked by a full path this value will get into `DT_NEEDED` + // instead of the full path, so the library can be later found in some other + // location than that specific path. + let mut soname = OsString::from("-soname="); + soname.push(name); + self.link_arg(soname); } } } } + + fn with_as_needed(&mut self, as_needed: bool, f: impl FnOnce(&mut Self)) { + if !as_needed { + if self.sess.target.is_like_osx { + // FIXME(81490): ld64 doesn't support these flags but macOS 11 + // has -needed-l{} / -needed_library {} + // but we have no way to detect that here. + self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--no-as-needed"); + } else { + self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); + } + } + + f(self); + + if !as_needed { + if self.sess.target.is_like_osx { + // See above FIXME comment + } else if self.is_gnu && !self.sess.target.is_like_windows { + self.link_arg("--as-needed"); + } + } + } } impl<'a> Linker for GccLinker<'a> { @@ -506,27 +536,18 @@ impl<'a> Linker for GccLinker<'a> { // to the linker. return; } - if !as_needed { - if self.sess.target.is_like_osx { - // FIXME(81490): ld64 doesn't support these flags but macOS 11 - // has -needed-l{} / -needed_library {} - // but we have no way to detect that here. - self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.link_arg("--no-as-needed"); - } else { - self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); - } - } self.hint_dynamic(); - self.link_or_cc_arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - if !as_needed { - if self.sess.target.is_like_osx { - // See above FIXME comment - } else if self.is_gnu && !self.sess.target.is_like_windows { - self.link_arg("--as-needed"); - } - } + self.with_as_needed(as_needed, |this| { + let colon = if verbatim && this.is_gnu { ":" } else { "" }; + this.link_or_cc_arg(format!("-l{colon}{name}")); + }); + } + + fn link_dylib_by_path(&mut self, path: &Path, as_needed: bool) { + self.hint_dynamic(); + self.with_as_needed(as_needed, |this| { + this.link_or_cc_arg(path); + }) } fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { @@ -861,6 +882,15 @@ impl<'a> Linker for MsvcLinker<'a> { self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + // When producing a dll, MSVC linker may not emit an implib file if the dll doesn't export + // any symbols, so we skip linking if the implib file is not present. + let implib_path = path.with_extension("dll.lib"); + if implib_path.exists() { + self.link_or_cc_arg(implib_path); + } + } + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; @@ -1083,6 +1113,10 @@ impl<'a> Linker for EmLinker<'a> { self.link_or_cc_args(&["-l", name]); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { self.link_or_cc_args(&["-l", name]); } @@ -1240,6 +1274,10 @@ impl<'a> Linker for WasmLd<'a> { self.link_or_cc_args(&["-l", name]); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { self.link_or_cc_args(&["-l", name]); @@ -1368,10 +1406,6 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - bug!("dylibs are not supported on L4Re"); - } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { @@ -1536,6 +1570,11 @@ impl<'a> Linker for AixLinker<'a> { self.link_or_cc_arg(format!("-l{name}")); } + fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { + self.hint_dynamic(); + self.link_or_cc_arg(path); + } + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { @@ -1721,10 +1760,6 @@ impl<'a> Linker for PtxLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1791,10 +1826,6 @@ impl<'a> Linker for LlbcLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } @@ -1866,10 +1897,6 @@ impl<'a> Linker for BpfLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") } diff --git a/tests/run-make/dylib-soname/foo.rs b/tests/run-make/dylib-soname/foo.rs new file mode 100644 index 0000000000000..6833f39199943 --- /dev/null +++ b/tests/run-make/dylib-soname/foo.rs @@ -0,0 +1 @@ +pub fn something() {} diff --git a/tests/run-make/dylib-soname/rmake.rs b/tests/run-make/dylib-soname/rmake.rs new file mode 100644 index 0000000000000..a0215a6906e47 --- /dev/null +++ b/tests/run-make/dylib-soname/rmake.rs @@ -0,0 +1,19 @@ +// Checks that produced dylibs have a relative SONAME set, so they don't put "unmovable" full paths +// into DT_NEEDED when used by a full path. + +//@ only-linux +//@ ignore-cross-compile + +use run_make_support::regex::Regex; +use run_make_support::{cmd, run_in_tmpdir, rustc}; + +fn main() { + run_in_tmpdir(|| { + rustc().crate_name("foo").crate_type("dylib").input("foo.rs").run(); + cmd("readelf") + .arg("-d") + .arg("libfoo.so") + .run() + .assert_stdout_contains("Library soname: [libfoo.so]"); + }); +} From edeebe675b39cbdca93ec5b4c79f9a0765678112 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Jul 2024 20:29:01 +1000 Subject: [PATCH 33/54] Import `std::{iter,mem}`. --- .../rustc_parse/src/parser/attr_wrapper.rs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 3afd178cc2b4e..13a647adfe3b5 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -9,6 +9,7 @@ use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; use std::ops::Range; +use std::{iter, mem}; /// A wrapper type to ensure that the parser handles outer attributes correctly. /// When we parse outer attributes, we need to ensure that we capture tokens @@ -53,7 +54,7 @@ impl AttrWrapper { // FIXME: require passing an NT to prevent misuse of this method pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) { let mut self_attrs = self.attrs; - std::mem::swap(attrs, &mut self_attrs); + mem::swap(attrs, &mut self_attrs); attrs.extend(self_attrs); } @@ -104,13 +105,12 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // produce an empty `TokenStream` if no calls were made, and omit the // final token otherwise. let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = - std::iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) - .chain(std::iter::repeat_with(|| { - let token = cursor_snapshot.next(); - (FlatToken::Token(token.0), token.1) - })) - .take(self.num_calls as usize); + let tokens = iter::once((FlatToken::Token(self.start_token.0.clone()), self.start_token.1)) + .chain(iter::repeat_with(|| { + let token = cursor_snapshot.next(); + (FlatToken::Token(token.0), token.1) + })) + .take(self.num_calls as usize); if self.replace_ranges.is_empty() { make_attr_token_stream(tokens, self.break_last_token) @@ -158,7 +158,7 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // This keeps the total length of `tokens` constant throughout the // replacement process, allowing us to use all of the `ReplaceRanges` entries // without adjusting indices. - let filler = std::iter::repeat((FlatToken::Empty, Spacing::Alone)) + let filler = iter::repeat((FlatToken::Empty, Spacing::Alone)) .take(range.len() - new_tokens.len()); tokens.splice( @@ -222,8 +222,7 @@ impl<'a> Parser<'a> { let replace_ranges_start = self.capture_state.replace_ranges.len(); let (mut ret, trailing) = { - let prev_capturing = - std::mem::replace(&mut self.capture_state.capturing, Capturing::Yes); + let prev_capturing = mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let ret_and_trailing = f(self, attrs.attrs); self.capture_state.capturing = prev_capturing; ret_and_trailing? From 371845b630a86f86233c4a031971f9737a2092ff Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 10:14:24 -0400 Subject: [PATCH 34/54] rewrite dylib-chain to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dylib-chain/Makefile | 13 ----------- tests/run-make/dylib-chain/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/dylib-chain/Makefile create mode 100644 tests/run-make/dylib-chain/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 276d2d694cda0..cd01b8596bba1 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -23,7 +23,6 @@ run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile -run-make/dylib-chain/Makefile run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile run-make/emit-to-stdout/Makefile diff --git a/tests/run-make/dylib-chain/Makefile b/tests/run-make/dylib-chain/Makefile deleted file mode 100644 index f1fea99c5ee91..0000000000000 --- a/tests/run-make/dylib-chain/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) m1.rs -C prefer-dynamic - $(RUSTC) m2.rs -C prefer-dynamic - $(RUSTC) m3.rs -C prefer-dynamic - $(RUSTC) m4.rs - $(call RUN,m4) - $(call REMOVE_DYLIBS,m1) - $(call REMOVE_DYLIBS,m2) - $(call REMOVE_DYLIBS,m3) - $(call FAIL,m4) diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs new file mode 100644 index 0000000000000..1d27191806f8b --- /dev/null +++ b/tests/run-make/dylib-chain/rmake.rs @@ -0,0 +1,22 @@ +// In this test, m4 depends on m3, which depends on m2, which depends on m1. +// Even though dependencies are chained like this and there is no direct mention +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Naturally, +// removing those dependencies should cause execution to fail. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc}; + +fn main() { + rustc().input("m1.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m2.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m3.rs").arg("-Cprefer-dynamic").run(); + rustc().input("m4.rs").run(); + run("m4"); + fs_wrapper::remove_file(dynamic_lib_name("m1")); + fs_wrapper::remove_file(dynamic_lib_name("m2")); + fs_wrapper::remove_file(dynamic_lib_name("m3")); + run_fail("m4"); +} From 86bd3498b2c5a6a40f3db62c48a22f81d7713950 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 10:20:49 -0400 Subject: [PATCH 35/54] rewrite rlib-chain to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/dylib-chain/rmake.rs | 5 ++-- tests/run-make/rlib-chain/Makefile | 11 --------- tests/run-make/rlib-chain/rmake.rs | 23 +++++++++++++++++++ 4 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/rlib-chain/Makefile create mode 100644 tests/run-make/rlib-chain/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index cd01b8596bba1..1e213eabab580 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -135,7 +135,6 @@ run-make/remap-path-prefix-dwarf/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile run-make/return-non-c-like-enum-from-c/Makefile -run-make/rlib-chain/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs index 1d27191806f8b..a96cc3508750b 100644 --- a/tests/run-make/dylib-chain/rmake.rs +++ b/tests/run-make/dylib-chain/rmake.rs @@ -1,7 +1,8 @@ // In this test, m4 depends on m3, which depends on m2, which depends on m1. // Even though dependencies are chained like this and there is no direct mention -// of m1 or m2 in m4.rs, compilation and execution should still succeed. Naturally, -// removing those dependencies should cause execution to fail. +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike the +// rlib-chain test, dynamic libraries contain upstream dependencies, and breaking +// the chain by removing the dylibs causes execution to fail. // See https://github.com/rust-lang/rust/issues/10434 //@ ignore-cross-compile diff --git a/tests/run-make/rlib-chain/Makefile b/tests/run-make/rlib-chain/Makefile deleted file mode 100644 index 7a1f887fa5271..0000000000000 --- a/tests/run-make/rlib-chain/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) m1.rs - $(RUSTC) m2.rs - $(RUSTC) m3.rs - $(RUSTC) m4.rs - $(call RUN,m4) - rm $(TMPDIR)/*lib - $(call RUN,m4) diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs new file mode 100644 index 0000000000000..0947262bf6200 --- /dev/null +++ b/tests/run-make/rlib-chain/rmake.rs @@ -0,0 +1,23 @@ +// In this test, m4 depends on m3, which depends on m2, which depends on m1. +// Even though dependencies are chained like this and there is no direct mention +// of m1 or m2 in m4.rs, compilation and execution should still succeed. Unlike +// the dylib-chain test, rlibs do not contain upstream dependencies, and removing +// the libraries still allows m4 to successfully execute. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{fs_wrapper, run, rust_lib_name, rustc}; + +fn main() { + rustc().input("m1.rs").run(); + rustc().input("m2.rs").run(); + rustc().input("m3.rs").run(); + rustc().input("m4.rs").run(); + run("m4"); + fs_wrapper::remove_file(rust_lib_name("m1")); + fs_wrapper::remove_file(rust_lib_name("m2")); + fs_wrapper::remove_file(rust_lib_name("m3")); + run("m4"); +} From 3a656462ef59a5d5288e0eb9651060d640c975ed Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:08:49 -0400 Subject: [PATCH 36/54] rewrite and rename issue-47384 to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../lib.rs | 0 .../linker.ld | 0 .../main.rs | 0 .../include-all-symbols-linking/rmake.rs | 29 +++++++++++++++++++ tests/run-make/issue-47384/Makefile | 12 -------- 6 files changed, 29 insertions(+), 13 deletions(-) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/lib.rs (100%) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/linker.ld (100%) rename tests/run-make/{issue-47384 => include-all-symbols-linking}/main.rs (100%) create mode 100644 tests/run-make/include-all-symbols-linking/rmake.rs delete mode 100644 tests/run-make/issue-47384/Makefile diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 1e213eabab580..6ef68509f1095 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -65,7 +65,6 @@ run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-37839/Makefile run-make/issue-40535/Makefile -run-make/issue-47384/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-83045/Makefile diff --git a/tests/run-make/issue-47384/lib.rs b/tests/run-make/include-all-symbols-linking/lib.rs similarity index 100% rename from tests/run-make/issue-47384/lib.rs rename to tests/run-make/include-all-symbols-linking/lib.rs diff --git a/tests/run-make/issue-47384/linker.ld b/tests/run-make/include-all-symbols-linking/linker.ld similarity index 100% rename from tests/run-make/issue-47384/linker.ld rename to tests/run-make/include-all-symbols-linking/linker.ld diff --git a/tests/run-make/issue-47384/main.rs b/tests/run-make/include-all-symbols-linking/main.rs similarity index 100% rename from tests/run-make/issue-47384/main.rs rename to tests/run-make/include-all-symbols-linking/main.rs diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs new file mode 100644 index 0000000000000..a443fc0a5c41b --- /dev/null +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -0,0 +1,29 @@ +// Linkers treat archives differently from object files: all object files participate in linking, +// while archives will only participate in linking if they can satisfy at least one undefined +// reference (version scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to +// be ignored by the linker, and since they never participate in the linking, using `KEEP` in the +// linker scripts can't keep them either. This causes #47384. After the fix in #95604, this test +// checks that these symbols and sections successfully appear in the output dynamic library. +// See https://github.com/rust-lang/rust/pull/95604 +// See https://github.com/rust-lang/rust/issues/47384 + +//FIXME(Oneirical): ignore flags: only linux and cross compile + +use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc}; + +fn main() { + rustc().crate_type("lib").input("lib.rs").run(); + rustc().crate_type("cdylib").link_args("-Tlinker.ld").input("main.rs").run(); + // Ensure `#[used]` and `KEEP`-ed section is there + llvm_objdump() + .arg("--full-contents") + .arg("--section=.static") + .input(dynamic_lib_name("main")) + .run(); + // Ensure `#[no_mangle]` symbol is there + llvm_readobj() + .arg("--symbols") + .input(dynamic_lib_name("main")) + .run() + .assert_stdout_contains("bar"); +} diff --git a/tests/run-make/issue-47384/Makefile b/tests/run-make/issue-47384/Makefile deleted file mode 100644 index afc77cb275aaa..0000000000000 --- a/tests/run-make/issue-47384/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# only-linux -# ignore-cross-compile - -all: main.rs - $(RUSTC) --crate-type lib lib.rs - $(RUSTC) --crate-type cdylib -Clink-args="-Tlinker.ld" main.rs - # Ensure `#[used]` and `KEEP`-ed section is there - objdump -s -j".static" $(TMPDIR)/libmain.so - # Ensure `#[no_mangle]` symbol is there - nm $(TMPDIR)/libmain.so | $(CGREP) bar From b75dd71ef0472a5ef2c7c1ec9f0a12b125905d02 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:28:50 -0400 Subject: [PATCH 37/54] rewrite msvc-opt-minsize to ui test --- tests/run-make/msvc-opt-minsize/Makefile | 6 ---- tests/run-make/msvc-opt-minsize/foo.rs | 19 ------------ .../{windows-subsystem => windows}/console.rs | 0 tests/ui/windows/msvc-opt-minsize.rs | 31 +++++++++++++++++++ .../windows-subsystem-invalid.rs | 0 .../windows-subsystem-invalid.stderr | 0 .../{windows-subsystem => windows}/windows.rs | 0 7 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 tests/run-make/msvc-opt-minsize/Makefile delete mode 100644 tests/run-make/msvc-opt-minsize/foo.rs rename tests/ui/{windows-subsystem => windows}/console.rs (100%) create mode 100644 tests/ui/windows/msvc-opt-minsize.rs rename tests/ui/{windows-subsystem => windows}/windows-subsystem-invalid.rs (100%) rename tests/ui/{windows-subsystem => windows}/windows-subsystem-invalid.stderr (100%) rename tests/ui/{windows-subsystem => windows}/windows.rs (100%) diff --git a/tests/run-make/msvc-opt-minsize/Makefile b/tests/run-make/msvc-opt-minsize/Makefile deleted file mode 100644 index 32e6e28018f7a..0000000000000 --- a/tests/run-make/msvc-opt-minsize/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs -Copt-level=z 2>&1 - $(call RUN,foo) diff --git a/tests/run-make/msvc-opt-minsize/foo.rs b/tests/run-make/msvc-opt-minsize/foo.rs deleted file mode 100644 index 3f5496c08ee25..0000000000000 --- a/tests/run-make/msvc-opt-minsize/foo.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(test)] -extern crate test; - -fn foo(x: i32, y: i32) -> i64 { - (x + y) as i64 -} - -#[inline(never)] -fn bar() { - let _f = Box::new(0); - // This call used to trigger an LLVM bug in opt-level z where the base - // pointer gets corrupted, see issue #45034 - let y: fn(i32, i32) -> i64 = test::black_box(foo); - test::black_box(y(1, 2)); -} - -fn main() { - bar(); -} diff --git a/tests/ui/windows-subsystem/console.rs b/tests/ui/windows/console.rs similarity index 100% rename from tests/ui/windows-subsystem/console.rs rename to tests/ui/windows/console.rs diff --git a/tests/ui/windows/msvc-opt-minsize.rs b/tests/ui/windows/msvc-opt-minsize.rs new file mode 100644 index 0000000000000..c1be168a05dde --- /dev/null +++ b/tests/ui/windows/msvc-opt-minsize.rs @@ -0,0 +1,31 @@ +// A previously outdated version of LLVM caused compilation failures on Windows +// specifically with optimization level `z`. After the update to a more recent LLVM +// version, this test checks that compilation and execution both succeed. +// See https://github.com/rust-lang/rust/issues/45034 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed +//@ only-windows +// Reason: the observed bug only occurs on Windows +//@ run-pass +//@ compile-flags: -C opt-level=z + +#![feature(test)] +extern crate test; + +fn foo(x: i32, y: i32) -> i64 { + (x + y) as i64 +} + +#[inline(never)] +fn bar() { + let _f = Box::new(0); + // This call used to trigger an LLVM bug in opt-level z where the base + // pointer gets corrupted, see issue #45034 + let y: fn(i32, i32) -> i64 = test::black_box(foo); + test::black_box(y(1, 2)); +} + +fn main() { + bar(); +} diff --git a/tests/ui/windows-subsystem/windows-subsystem-invalid.rs b/tests/ui/windows/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows-subsystem/windows-subsystem-invalid.rs rename to tests/ui/windows/windows-subsystem-invalid.rs diff --git a/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr b/tests/ui/windows/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows-subsystem/windows-subsystem-invalid.stderr rename to tests/ui/windows/windows-subsystem-invalid.stderr diff --git a/tests/ui/windows-subsystem/windows.rs b/tests/ui/windows/windows.rs similarity index 100% rename from tests/ui/windows-subsystem/windows.rs rename to tests/ui/windows/windows.rs From 45313a6ca038995bc3a0cc952fac94102d00f60c Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 27 Jun 2024 11:44:47 -0400 Subject: [PATCH 38/54] rewrite test-harness to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 2 -- src/tools/tidy/src/ui_tests.rs | 2 +- .../include-all-symbols-linking/rmake.rs | 4 ++- tests/run-make/test-harness/Makefile | 9 ------- tests/run-make/test-harness/rmake.rs | 25 +++++++++++++++++++ tests/ui/{windows => }/msvc-opt-minsize.rs | 0 .../{windows => windows-subsystem}/console.rs | 0 .../windows-subsystem-invalid.rs | 0 .../windows-subsystem-invalid.stderr | 0 .../{windows => windows-subsystem}/windows.rs | 0 10 files changed, 29 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/test-harness/Makefile create mode 100644 tests/run-make/test-harness/rmake.rs rename tests/ui/{windows => }/msvc-opt-minsize.rs (100%) rename tests/ui/{windows => windows-subsystem}/console.rs (100%) rename tests/ui/{windows => windows-subsystem}/windows-subsystem-invalid.rs (100%) rename tests/ui/{windows => windows-subsystem}/windows-subsystem-invalid.stderr (100%) rename tests/ui/{windows => windows-subsystem}/windows.rs (100%) diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6ef68509f1095..2da4e476e9016 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -96,7 +96,6 @@ run-make/metadata-dep-info/Makefile run-make/min-global-align/Makefile run-make/missing-crate-dependency/Makefile run-make/mixing-libs/Makefile -run-make/msvc-opt-minsize/Makefile run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile @@ -163,7 +162,6 @@ run-make/target-cpu-native/Makefile run-make/target-specs/Makefile run-make/target-without-atomic-cas/Makefile run-make/test-benches/Makefile -run-make/test-harness/Makefile run-make/thumb-none-cortex-m/Makefile run-make/thumb-none-qemu/Makefile run-make/track-path-dep-info/Makefile diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 95857502108da..5e6992038e395 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -13,7 +13,7 @@ use std::path::{Path, PathBuf}; // should all be 1000 or lower. Limits significantly smaller than 1000 are also // desirable, because large numbers of files are unwieldy in general. See issue // #73494. -const ENTRY_LIMIT: u32 = 900; +const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: u32 = 1672; diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs index a443fc0a5c41b..77fd71ab20d21 100644 --- a/tests/run-make/include-all-symbols-linking/rmake.rs +++ b/tests/run-make/include-all-symbols-linking/rmake.rs @@ -7,7 +7,9 @@ // See https://github.com/rust-lang/rust/pull/95604 // See https://github.com/rust-lang/rust/issues/47384 -//FIXME(Oneirical): ignore flags: only linux and cross compile +//@ only-linux +// Reason: differences in object file formats on OSX and Windows +// causes errors in the llvm_objdump step use run_make_support::{dynamic_lib_name, llvm_objdump, llvm_readobj, rustc}; diff --git a/tests/run-make/test-harness/Makefile b/tests/run-make/test-harness/Makefile deleted file mode 100644 index ee8c9294f91ab..0000000000000 --- a/tests/run-make/test-harness/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - # check that #[cfg_attr(..., ignore)] does the right thing. - $(RUSTC) --test test-ignore-cfg.rs --cfg ignorecfg - $(call RUN,test-ignore-cfg) | $(CGREP) 'shouldnotignore ... ok' 'shouldignore ... ignored' - $(call RUN,test-ignore-cfg --quiet) | $(CGREP) -e "^i\.$$" - $(call RUN,test-ignore-cfg --quiet) | $(CGREP) -v 'should' diff --git a/tests/run-make/test-harness/rmake.rs b/tests/run-make/test-harness/rmake.rs new file mode 100644 index 0000000000000..30b3d00f4d114 --- /dev/null +++ b/tests/run-make/test-harness/rmake.rs @@ -0,0 +1,25 @@ +// The way test suites run can be modified using configuration flags, +// ignoring certain tests while running others. This test contains two +// functions, one which must run and the other which must not. The standard +// output is checked to verify that the ignore configuration is doing its job, +// and that output is successfully minimized with the --quiet flag. +// See https://github.com/rust-lang/rust/commit/f7ebe23ae185991b0fee05b32fbb3e29b89a41bf + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{run, run_with_args, rustc}; + +fn main() { + rustc().arg("--test").input("test-ignore-cfg.rs").cfg("ignorecfg").run(); + // check that #[cfg_attr(..., ignore)] does the right thing. + run("test-ignore-cfg") + .assert_stdout_contains("shouldnotignore ... ok") + .assert_stdout_contains("shouldignore ... ignored"); + assert_eq!( + // One of the lines is exactly "i." + run_with_args("test-ignore-cfg", &["--quiet"]).stdout_utf8().lines().find(|&x| x == "i."), + Some("i.") + ); + run_with_args("test-ignore-cfg", &["--quiet"]).assert_stdout_not_contains("should"); +} diff --git a/tests/ui/windows/msvc-opt-minsize.rs b/tests/ui/msvc-opt-minsize.rs similarity index 100% rename from tests/ui/windows/msvc-opt-minsize.rs rename to tests/ui/msvc-opt-minsize.rs diff --git a/tests/ui/windows/console.rs b/tests/ui/windows-subsystem/console.rs similarity index 100% rename from tests/ui/windows/console.rs rename to tests/ui/windows-subsystem/console.rs diff --git a/tests/ui/windows/windows-subsystem-invalid.rs b/tests/ui/windows-subsystem/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows/windows-subsystem-invalid.rs rename to tests/ui/windows-subsystem/windows-subsystem-invalid.rs diff --git a/tests/ui/windows/windows-subsystem-invalid.stderr b/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows/windows-subsystem-invalid.stderr rename to tests/ui/windows-subsystem/windows-subsystem-invalid.stderr diff --git a/tests/ui/windows/windows.rs b/tests/ui/windows-subsystem/windows.rs similarity index 100% rename from tests/ui/windows/windows.rs rename to tests/ui/windows-subsystem/windows.rs From d3a742bde999add41c002513fccd0949859128f4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 12:53:03 -0400 Subject: [PATCH 39/54] Miscellaneous renaming --- .../src/interpret/terminator.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/instance.rs | 120 +++++++++--------- .../src/traits/vtable.rs | 6 +- compiler/rustc_ty_utils/src/instance.rs | 4 +- 5 files changed, 71 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 74521d0f49345..f59293e7266ac 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -883,13 +883,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - let concrete_method = Instance::resolve_for_vtable( + let concrete_method = Instance::expect_resolve_for_vtable( tcx, self.param_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), - ) - .unwrap(); + ); assert_eq!(fn_inst, concrete_method); } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d40a783358959..33c27d41d8642 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2197,8 +2197,8 @@ rustc_queries! { /// * `Err(ErrorGuaranteed)` when the `Instance` resolution process /// couldn't complete due to errors elsewhere - this is distinct /// from `Ok(None)` to avoid misleading diagnostics when an error - /// has already been/will be emitted, for the original cause - query resolve_instance( + /// has already been/will be emitted, for the original cause. + query resolve_instance_raw( key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)> ) -> Result>, ErrorGuaranteed> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1ba8820e0e11d..99ac503cd6800 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -505,7 +505,7 @@ impl<'tcx> Instance<'tcx> { // below is more likely to ignore the bounds in scope (e.g. if the only // generic parameters mentioned by `args` were lifetime ones). let args = tcx.erase_regions(args); - tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, args)))) + tcx.resolve_instance_raw(tcx.erase_regions(param_env.and((def_id, args)))) } pub fn expect_resolve( @@ -571,77 +571,81 @@ impl<'tcx> Instance<'tcx> { }) } - pub fn resolve_for_vtable( + pub fn expect_resolve_for_vtable( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, - ) -> Option> { + ) -> Instance<'tcx> { debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args); let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); let is_vtable_shim = !fn_sig.inputs().skip_binder().is_empty() && fn_sig.input(0).skip_binder().is_param(0) && tcx.generics_of(def_id).has_self; + if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceKind::VTableShim(def_id), args }) - } else { - let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); - Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { - match resolved.def { - InstanceKind::Item(def) => { - // We need to generate a shim when we cannot guarantee that - // the caller of a trait object method will be aware of - // `#[track_caller]` - this ensures that the caller - // and callee ABI will always match. - // - // The shim is generated when all of these conditions are met: - // - // 1) The underlying method expects a caller location parameter - // in the ABI - if resolved.def.requires_caller_location(tcx) - // 2) The caller location parameter comes from having `#[track_caller]` - // on the implementation, and *not* on the trait method. - && !tcx.should_inherit_track_caller(def) - // If the method implementation comes from the trait definition itself - // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), - // then we don't need to generate a shim. This check is needed because - // `should_inherit_track_caller` returns `false` if our method - // implementation comes from the trait block, and not an impl block - && !matches!( - tcx.opt_associated_item(def), - Some(ty::AssocItem { - container: ty::AssocItemContainer::TraitContainer, - .. - }) - ) - { - if tcx.is_closure_like(def) { - debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", - def, def_id, args); - - // Create a shim for the `FnOnce/FnMut/Fn` method we are calling - // - unlike functions, invoking a closure always goes through a - // trait. - resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; - } else { - debug!( - " => vtable fn pointer created for function with #[track_caller]: {:?}", def - ); - resolved.def = InstanceKind::ReifyShim(def, reason); - } - } - } - InstanceKind::Virtual(def_id, _) => { - debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceKind::ReifyShim(def_id, reason) + return Instance { def: InstanceKind::VTableShim(def_id), args }; + } + + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args); + + let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); + match resolved.def { + InstanceKind::Item(def) => { + // We need to generate a shim when we cannot guarantee that + // the caller of a trait object method will be aware of + // `#[track_caller]` - this ensures that the caller + // and callee ABI will always match. + // + // The shim is generated when all of these conditions are met: + // + // 1) The underlying method expects a caller location parameter + // in the ABI + if resolved.def.requires_caller_location(tcx) + // 2) The caller location parameter comes from having `#[track_caller]` + // on the implementation, and *not* on the trait method. + && !tcx.should_inherit_track_caller(def) + // If the method implementation comes from the trait definition itself + // (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`), + // then we don't need to generate a shim. This check is needed because + // `should_inherit_track_caller` returns `false` if our method + // implementation comes from the trait block, and not an impl block + && !matches!( + tcx.opt_associated_item(def), + Some(ty::AssocItem { + container: ty::AssocItemContainer::TraitContainer, + .. + }) + ) + { + if tcx.is_closure_like(def) { + debug!( + " => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", + def, def_id, args + ); + + // Create a shim for the `FnOnce/FnMut/Fn` method we are calling + // - unlike functions, invoking a closure always goes through a + // trait. + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; + } else { + debug!( + " => vtable fn pointer created for function with #[track_caller]: {:?}", + def + ); + resolved.def = InstanceKind::ReifyShim(def, reason); } - _ => {} } - - resolved - }) + } + InstanceKind::Virtual(def_id, _) => { + debug!(" => vtable fn pointer created for virtual call"); + resolved.def = InstanceKind::ReifyShim(def_id, reason) + } + _ => {} } + + resolved } pub fn resolve_closure( diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index e54ced85deeb7..e710b17a10d6e 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -285,13 +285,13 @@ fn vtable_entries<'tcx>( return VtblEntry::Vacant; } - let instance = ty::Instance::resolve_for_vtable( + let instance = ty::Instance::expect_resolve_for_vtable( tcx, ty::ParamEnv::reveal_all(), def_id, args, - ) - .expect("resolution failed during building vtable representation"); + ); + VtblEntry::Method(instance) }); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index c50a490a9dc0c..7b6d86d22a578 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -16,7 +16,7 @@ use traits::{translate_args, Reveal}; use crate::errors::UnexpectedFnPtrAssociatedItem; -fn resolve_instance<'tcx>( +fn resolve_instance_raw<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, GenericArgsRef<'tcx>)>, ) -> Result>, ErrorGuaranteed> { @@ -364,5 +364,5 @@ fn resolve_associated_item<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { resolve_instance, ..*providers }; + *providers = Providers { resolve_instance_raw, ..*providers }; } From 9dc129ae829f8f322421dc9fb2c64d58e11eb08a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 13:06:23 -0400 Subject: [PATCH 40/54] Give Instance::expect_resolve a span --- .../rustc_codegen_cranelift/src/abi/mod.rs | 11 +++++++--- .../rustc_codegen_cranelift/src/main_shim.rs | 2 ++ compiler/rustc_codegen_gcc/src/context.rs | 1 + compiler/rustc_codegen_llvm/src/context.rs | 1 + compiler/rustc_codegen_ssa/src/base.rs | 1 + compiler/rustc_codegen_ssa/src/mir/block.rs | 1 + .../src/const_eval/machine.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 12 ++++++----- compiler/rustc_monomorphize/src/collector.rs | 20 +++++++++++++++---- 9 files changed, 38 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 0d7eee7afb41e..81dfde81e938c 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -371,9 +371,14 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Handle special calls like intrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, fn_args) = *func.layout().ty.kind() { - let instance = - ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args) - .polymorphize(fx.tcx); + let instance = ty::Instance::expect_resolve( + fx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + fn_args, + Some(source_info.span), + ) + .polymorphize(fx.tcx); if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 33d3f9b8a90a3..d1dc147dba8f8 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -119,6 +119,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), + None, ) .polymorphize(tcx); @@ -144,6 +145,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), + None, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 6231b09552cea..88ffcd7f4b502 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -479,6 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), + None, ); let symbol_name = tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1a8e8efdae507..a012c40ec0a6f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -580,6 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), + None, )), _ => { let name = name.unwrap_or("rust_eh_personality"); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index c18816533a2fb..1be4cb186a7e9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -467,6 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty::ParamEnv::reveal_all(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), + None, ); let start_fn = cx.get_fn_addr(start_instance); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b1c22faf1ae9d..8b302b59e1312 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -842,6 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), def_id, args, + Some(fn_span), ) .polymorphize(bx.tcx()), ), diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 99276bac03501..cb3288402c11b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -253,6 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ty::ParamEnv::reveal_all(), const_def_id, instance.args, + Some(self.find_closest_untracked_caller_location()), ); return Ok(Some(new_instance)); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 99ac503cd6800..6d7c04fca4b94 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -13,7 +13,7 @@ use rustc_macros::{ }; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::Symbol; +use rustc_span::{Span, Symbol}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -513,10 +513,12 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, + span: Option, ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, - instance => bug!( + instance => span_bug!( + span.unwrap_or(tcx.def_span(def_id)), "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_args(def_id, args) ), @@ -588,7 +590,7 @@ impl<'tcx> Instance<'tcx> { return Instance { def: InstanceKind::VTableShim(def_id), args }; } - let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args); + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, None); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); match resolved.def { @@ -665,13 +667,13 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 235743fccc89e..8915876226572 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -916,7 +916,13 @@ fn visit_fn_use<'tcx>( ) { if let ty::FnDef(def_id, args) = *ty.kind() { let instance = if is_direct_call { - ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args) + ty::Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + Some(source), + ) } else { match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) { Some(instance) => instance, @@ -1318,8 +1324,13 @@ fn visit_mentioned_item<'tcx>( match *item { MentionedItem::Fn(ty) => { if let ty::FnDef(def_id, args) = *ty.kind() { - let instance = - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args); + let instance = Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + Some(span), + ); // `visit_instance_use` was written for "used" item collection but works just as well // for "mentioned" item collection. // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway @@ -1544,6 +1555,7 @@ impl<'v> RootCollector<'_, 'v> { ty::ParamEnv::reveal_all(), start_def_id, self.tcx.mk_args(&[main_ret_ty.into()]), + None, ); self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); @@ -1614,7 +1626,7 @@ fn create_mono_items_for_default_impls<'tcx>( // As mentioned above, the method is legal to eagerly instantiate if it // only has lifetime generic parameters. This is validated by let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); - let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args); + let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, None); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { From 0f7f3f4045a3b34678584a4148ff452f8a072904 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 May 2024 14:09:40 -0400 Subject: [PATCH 41/54] Re-implement a type-size based limit --- compiler/rustc_middle/messages.ftl | 6 ++ compiler/rustc_middle/src/error.rs | 14 ++++ compiler/rustc_middle/src/middle/limits.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 82 +++++++++++++++++-- compiler/rustc_middle/src/ty/print/mod.rs | 32 +++++++- compiler/rustc_monomorphize/messages.ftl | 5 -- compiler/rustc_monomorphize/src/collector.rs | 69 +--------------- compiler/rustc_monomorphize/src/errors.rs | 13 --- ...issue-72408-nested-closures-exponential.rs | 4 +- ...e-72408-nested-closures-exponential.stderr | 10 +++ tests/ui/codegen/overflow-during-mono.rs | 1 - tests/ui/codegen/overflow-during-mono.stderr | 11 +-- tests/ui/issues/issue-22638.rs | 5 +- tests/ui/issues/issue-22638.stderr | 17 ++-- .../issue-37311.rs | 4 +- .../issue-37311.stderr | 10 +-- .../issue-58952-filter-type-length.rs | 7 +- .../issue-58952-filter-type-length.stderr | 8 ++ .../ui/iterators/iter-map-fold-type-length.rs | 2 +- tests/ui/recursion/issue-83150.rs | 5 +- tests/ui/recursion/issue-83150.stderr | 16 ++-- .../traits/issue-91949-hangs-on-recursion.rs | 6 +- .../issue-91949-hangs-on-recursion.stderr | 20 ++--- tests/ui/type_length_limit.rs | 4 +- tests/ui/type_length_limit.stderr | 13 ++- 25 files changed, 206 insertions(+), 160 deletions(-) create mode 100644 tests/ui/closures/issue-72408-nested-closures-exponential.stderr create mode 100644 tests/ui/iterators/issue-58952-filter-type-length.stderr diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index f4d619329eb9c..2b9d9a07a98ef 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -41,6 +41,9 @@ middle_cannot_be_normalized = middle_conflict_types = this expression supplies two conflicting concrete types for the same opaque type +middle_consider_type_length_limit = + consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate + middle_const_eval_non_int = constant evaluation of enum discriminant resulted in non-integer @@ -94,8 +97,11 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute +middle_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` + middle_unknown_layout = the type `{$ty}` has an unknown layout middle_values_too_big = values of the type `{$ty}` are too big for the current architecture +middle_written_to_path = the full type name has been written to '{$path}' diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 6e622b0405f0a..711db4e0a6bdb 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::path::PathBuf; use rustc_errors::{codes::*, DiagArgName, DiagArgValue, DiagMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -149,3 +150,16 @@ pub struct ErroneousConstant { /// Used by `rustc_const_eval` pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; + +#[derive(Diagnostic)] +#[diag(middle_type_length_limit)] +#[help(middle_consider_type_length_limit)] +pub struct TypeLengthLimit { + #[primary_span] + pub span: Span, + pub shrunk: String, + #[note(middle_written_to_path)] + pub was_written: Option<()>, + pub path: PathBuf, + pub type_length: usize, +} diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 4d69801274956..d0b4f36a426fd 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -30,7 +30,7 @@ pub fn provide(providers: &mut Providers) { tcx.hir().krate_attrs(), tcx.sess, sym::type_length_limit, - 1048576, + 2usize.pow(24), ), } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6d7c04fca4b94..65039d8b52c22 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,23 +1,25 @@ +use crate::error; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use crate::ty::print::{FmtPrinter, Printer}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable}; -use crate::ty::{EarlyBinder, GenericArgs, GenericArgsRef, TypeVisitableExt}; +use crate::ty::print::{shrunk_instance_name, FmtPrinter, Printer}; +use crate::ty::{ + self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::FiniteBitSet; -use rustc_macros::{ - Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable, TypeVisitable, -}; +use rustc_macros::{Decodable, Encodable, HashStable, Lift, TyDecodable, TyEncodable}; use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, DUMMY_SP}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; use std::fmt; +use std::path::PathBuf; /// An `InstanceKind` along with the args that are needed to substitute the instance. /// @@ -385,7 +387,28 @@ impl<'tcx> InstanceKind<'tcx> { } } -fn fmt_instance( +fn type_length<'tcx>(item: impl TypeVisitable>) -> usize { + struct Visitor { + type_length: usize, + } + impl<'tcx> TypeVisitor> for Visitor { + fn visit_ty(&mut self, t: Ty<'tcx>) { + self.type_length += 1; + t.super_visit_with(self); + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) { + self.type_length += 1; + ct.super_visit_with(self); + } + } + let mut visitor = Visitor { type_length: 0 }; + item.visit_with(&mut visitor); + + visitor.type_length +} + +pub fn fmt_instance( f: &mut fmt::Formatter<'_>, instance: Instance<'_>, type_length: Option, @@ -485,7 +508,8 @@ impl<'tcx> Instance<'tcx> { /// /// Presuming that coherence and type-check have succeeded, if this method is invoked /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return - /// `Ok(Some(instance))`. + /// `Ok(Some(instance))`, **except** for when the instance's inputs hit the type size limit, + /// in which case it may bail out and return `Ok(None)`. /// /// Returns `Err(ErrorGuaranteed)` when the `Instance` resolution process /// couldn't complete due to errors elsewhere - this is distinct @@ -498,6 +522,16 @@ impl<'tcx> Instance<'tcx> { def_id: DefId, args: GenericArgsRef<'tcx>, ) -> Result>, ErrorGuaranteed> { + // Rust code can easily create exponentially-long types using only a + // polynomial recursion depth. Even with the default recursion + // depth, you can easily get cases that take >2^60 steps to run, + // which means that rustc basically hangs. + // + // Bail out in these cases to avoid that bad user experience. + if !tcx.type_length_limit().value_within_limit(type_length(args)) { + return Ok(None); + } + // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. @@ -517,6 +551,36 @@ impl<'tcx> Instance<'tcx> { ) -> Instance<'tcx> { match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, + Ok(None) => { + let type_length = type_length(args); + if !tcx.type_length_limit().value_within_limit(type_length) { + let (shrunk, written_to_path) = + shrunk_instance_name(tcx, Instance::new(def_id, args)); + let mut path = PathBuf::new(); + let was_written = if let Some(path2) = written_to_path { + path = path2; + Some(()) + } else { + None + }; + tcx.dcx().emit_fatal(error::TypeLengthLimit { + // We don't use `def_span(def_id)` so that diagnostics point + // to the crate root during mono instead of to foreign items. + // This is arguably better. + span: span.unwrap_or(DUMMY_SP), + shrunk, + was_written, + path, + type_length, + }); + } else { + span_bug!( + span.unwrap_or(tcx.def_span(def_id)), + "failed to resolve instance for {}", + tcx.def_path_str_with_args(def_id, args) + ) + } + } instance => span_bug!( span.unwrap_or(tcx.def_span(def_id)), "failed to resolve instance for {}: {instance:#?}", diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 3c27df9529aa1..c165790548d75 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,5 +1,7 @@ +use std::path::PathBuf; + use crate::ty::GenericArg; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, ShortInstance, Ty, TyCtxt}; use hir::def::Namespace; use rustc_data_structures::fx::FxHashSet; @@ -356,3 +358,31 @@ where with_no_trimmed_paths!(Self::print(t, fmt)) } } + +/// Format instance name that is already known to be too long for rustc. +/// Show only the first 2 types if it is longer than 32 characters to avoid blasting +/// the user's terminal with thousands of lines of type-name. +/// +/// If the type name is longer than before+after, it will be written to a file. +pub fn shrunk_instance_name<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::Instance<'tcx>, +) -> (String, Option) { + let s = instance.to_string(); + + // Only use the shrunk version if it's really shorter. + // This also avoids the case where before and after slices overlap. + if s.chars().nth(33).is_some() { + let shrunk = format!("{}", ShortInstance(instance, 4)); + if shrunk == s { + return (s, None); + } + + let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); + let written_to_path = std::fs::write(&path, s).ok().map(|_| path); + + (shrunk, written_to_path) + } else { + (s, None) + } +} diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 94b553a07a755..7210701d4828c 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,6 +1,3 @@ -monomorphize_consider_type_length_limit = - consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate - monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} @@ -25,8 +22,6 @@ monomorphize_start_not_found = using `fn main` requires the standard library monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined -monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}` - monomorphize_unknown_cgu_collection_mode = unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 8915876226572..f98d4700528d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -222,12 +222,12 @@ use rustc_middle::mir::{self, Location, MentionedItem}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{shrunk_instance_name, with_no_trimmed_paths}; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{ self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; -use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::{bug, span_bug}; use rustc_session::config::EntryFnType; use rustc_session::Limit; @@ -238,9 +238,7 @@ use rustc_target::abi::Size; use std::path::PathBuf; use tracing::{debug, instrument, trace}; -use crate::errors::{ - self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit, TypeLengthLimit, -}; +use crate::errors::{self, EncounteredErrorWhileInstantiating, NoOptimizedMir, RecursionLimit}; use move_check::MoveCheckState; #[derive(PartialEq)] @@ -443,7 +441,6 @@ fn collect_items_rec<'tcx>( recursion_depths, recursion_limit, )); - check_type_length_limit(tcx, instance); rustc_data_structures::stack::ensure_sufficient_stack(|| { collect_items_of_instance( @@ -554,34 +551,6 @@ fn collect_items_rec<'tcx>( } } -/// Format instance name that is already known to be too long for rustc. -/// Show only the first 2 types if it is longer than 32 characters to avoid blasting -/// the user's terminal with thousands of lines of type-name. -/// -/// If the type name is longer than before+after, it will be written to a file. -fn shrunk_instance_name<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, -) -> (String, Option) { - let s = instance.to_string(); - - // Only use the shrunk version if it's really shorter. - // This also avoids the case where before and after slices overlap. - if s.chars().nth(33).is_some() { - let shrunk = format!("{}", ty::ShortInstance(instance, 4)); - if shrunk == s { - return (s, None); - } - - let path = tcx.output_filenames(()).temp_path_ext("long-type.txt", None); - let written_to_path = std::fs::write(&path, s).ok().map(|_| path); - - (shrunk, written_to_path) - } else { - (s, None) - } -} - fn check_recursion_limit<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -630,38 +599,6 @@ fn check_recursion_limit<'tcx>( (def_id, recursion_depth) } -fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { - let type_length = instance - .args - .iter() - .flat_map(|arg| arg.walk()) - .filter(|arg| match arg.unpack() { - GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, - GenericArgKind::Lifetime(_) => false, - }) - .count(); - debug!(" => type length={}", type_length); - - // Rust code can easily create exponentially-long types using only a - // polynomial recursion depth. Even with the default recursion - // depth, you can easily get cases that take >2^60 steps to run, - // which means that rustc basically hangs. - // - // Bail out in these cases to avoid that bad user experience. - if !tcx.type_length_limit().value_within_limit(type_length) { - let (shrunk, written_to_path) = shrunk_instance_name(tcx, instance); - let span = tcx.def_span(instance.def_id()); - let mut path = PathBuf::new(); - let was_written = if let Some(path2) = written_to_path { - path = path2; - Some(()) - } else { - None - }; - tcx.dcx().emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length }); - } -} - struct MirUsedCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index c0d1efd96c5b7..9548c46e6fa04 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -19,19 +19,6 @@ pub struct RecursionLimit { pub path: PathBuf, } -#[derive(Diagnostic)] -#[diag(monomorphize_type_length_limit)] -#[help(monomorphize_consider_type_length_limit)] -pub struct TypeLengthLimit { - #[primary_span] - pub span: Span, - pub shrunk: String, - #[note(monomorphize_written_to_path)] - pub was_written: Option<()>, - pub path: PathBuf, - pub type_length: usize, -} - #[derive(Diagnostic)] #[diag(monomorphize_no_optimized_mir)] pub struct NoOptimizedMir { diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.rs b/tests/ui/closures/issue-72408-nested-closures-exponential.rs index 682508f928082..033e422433861 100644 --- a/tests/ui/closures/issue-72408-nested-closures-exponential.rs +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.rs @@ -1,5 +1,4 @@ -//@ build-pass -//@ ignore-compare-mode-next-solver (hangs) +//@ build-fail // Closures include captured types twice in a type tree. // @@ -46,6 +45,7 @@ fn main() { let f = dup(f); let f = dup(f); + //~^ ERROR reached the type-length limit let f = dup(f); let f = dup(f); let f = dup(f); diff --git a/tests/ui/closures/issue-72408-nested-closures-exponential.stderr b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr new file mode 100644 index 0000000000000..2120b45696392 --- /dev/null +++ b/tests/ui/closures/issue-72408-nested-closures-exponential.stderr @@ -0,0 +1,10 @@ +error: reached the type-length limit while instantiating `dup::<{closure@$DIR/issue-72408-nested-closures-exponential.rs:13:5: 13:13}>` + --> $DIR/issue-72408-nested-closures-exponential.rs:47:13 + | +LL | let f = dup(f); + | ^^^^^^ + | + = help: consider adding a `#![type_length_limit="29360121"]` attribute to your crate + +error: aborting due to 1 previous error + diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 919f1a8120e0b..278298f27ff0e 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,5 +1,4 @@ //@ build-fail -//~^ ERROR overflow evaluating the requirement #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index f7a3e2df3dbaa..9e463378004dc 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,11 +1,8 @@ -error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized` +error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:12:41: 12:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` + --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`) - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` - = note: 31 redundant requirements hidden - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator` - = note: required for `Filter, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `IntoIterator` + = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/codegen/overflow-during-mono/overflow-during-mono.long-type.txt' error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/issues/issue-22638.rs b/tests/ui/issues/issue-22638.rs index 3e04eb41b98de..3e401e99fb48d 100644 --- a/tests/ui/issues/issue-22638.rs +++ b/tests/ui/issues/issue-22638.rs @@ -1,7 +1,4 @@ //@ build-fail -//@ normalize-stderr-test: "<\{closure@.+`" -> "$$CLOSURE`" -//@ normalize-stderr-test: ".nll/" -> "/" -//@ ignore-compare-mode-next-solver (hangs) #![allow(unused)] @@ -43,6 +40,7 @@ impl C { pub fn matches(&self, f: &F) { let &C(ref base) = self; base.matches(&|| { + //~^ ERROR reached the type-length limit C(base.clone()).matches(f) }) } @@ -55,7 +53,6 @@ impl D { pub fn matches(&self, f: &F) { let &D(ref a) = self; a.matches(f) - //~^ ERROR reached the recursion limit while instantiating `A::matches::<{closure } } diff --git a/tests/ui/issues/issue-22638.stderr b/tests/ui/issues/issue-22638.stderr index 45290f6afe9de..1344409c77040 100644 --- a/tests/ui/issues/issue-22638.stderr +++ b/tests/ui/issues/issue-22638.stderr @@ -1,14 +1,13 @@ -error: reached the recursion limit while instantiating `A::matches::$CLOSURE` - --> $DIR/issue-22638.rs:57:9 +error: reached the type-length limit while instantiating `D::matches::<{closure@$DIR/issue-22638.rs:42:23: 42:25}>` + --> $DIR/issue-22638.rs:42:9 | -LL | a.matches(f) - | ^^^^^^^^^^^^ +LL | / base.matches(&|| { +LL | | +LL | | C(base.clone()).matches(f) +LL | | }) + | |__________^ | -note: `A::matches` defined here - --> $DIR/issue-22638.rs:16:5 - | -LL | pub fn matches(&self, f: &F) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding a `#![type_length_limit="30408681"]` attribute to your crate error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs index 1646f16e1ecea..131c7535537f6 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,6 +1,5 @@ //@ build-fail //@ normalize-stderr-test: ".nll/" -> "/" -//@ ignore-compare-mode-next-solver (hangs) trait Mirror { type Image; @@ -15,7 +14,8 @@ trait Foo { impl Foo for T { #[allow(unconditional_recursion)] fn recurse(&self) { - (self, self).recurse(); //~ ERROR reached the recursion limit + (self, self).recurse(); + //~^ ERROR reached the type-length limit } } diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index ccee9ed4daadb..2978ced527949 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,14 +1,10 @@ -error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:18:9 +error: reached the type-length limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` + --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | -note: `::recurse` defined here - --> $DIR/issue-37311.rs:17:5 - | -LL | fn recurse(&self) { - | ^^^^^^^^^^^^^^^^^ + = help: consider adding a `#![type_length_limit="33554429"]` attribute to your crate = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index 9904eddb598ce..b2c208ae28f19 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,5 +1,4 @@ -//@ run-pass -//@ ignore-compare-mode-next-solver (hangs) +//@ build-fail //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. @@ -30,5 +29,9 @@ fn main() { .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) + .filter(|a| b.clone().any(|b| *b == *a)) .collect::>(); } diff --git a/tests/ui/iterators/issue-58952-filter-type-length.stderr b/tests/ui/iterators/issue-58952-filter-type-length.stderr new file mode 100644 index 0000000000000..975fcd4afffee --- /dev/null +++ b/tests/ui/iterators/issue-58952-filter-type-length.stderr @@ -0,0 +1,8 @@ +error: reached the type-length limit while instantiating ` as Iterator>::try_fold::, {closure@iter::adapters::filter::filter_try_fold<'_, ..., ..., ..., ..., ...>::{closure#0}}, ...>` + --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL + | + = help: consider adding a `#![type_length_limit="21233607"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/iterators/issue-58952-filter-type-length/issue-58952-filter-type-length.long-type.txt' + +error: aborting due to 1 previous error + diff --git a/tests/ui/iterators/iter-map-fold-type-length.rs b/tests/ui/iterators/iter-map-fold-type-length.rs index 6444fb9dada98..5f9567d68e819 100644 --- a/tests/ui/iterators/iter-map-fold-type-length.rs +++ b/tests/ui/iterators/iter-map-fold-type-length.rs @@ -3,7 +3,7 @@ //! //! The normal limit is a million, and this test used to exceed 1.5 million, but //! now we can survive an even tighter limit. Still seems excessive though... -#![type_length_limit = "256000"] +#![type_length_limit = "1327047"] // Custom wrapper so Iterator methods aren't specialized. struct Iter(I); diff --git a/tests/ui/recursion/issue-83150.rs b/tests/ui/recursion/issue-83150.rs index b74b2adfeab47..b3ddf88c4493f 100644 --- a/tests/ui/recursion/issue-83150.rs +++ b/tests/ui/recursion/issue-83150.rs @@ -1,7 +1,6 @@ //@ build-fail //@ compile-flags: -Copt-level=0 //@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -//~^^^ ERROR overflow evaluating the requirement //@ ignore-compare-mode-next-solver (hangs) fn main() { @@ -9,6 +8,8 @@ fn main() { func(&mut iter) } -fn func>(iter: &mut T) { //~ WARN function cannot return without recursing +fn func>(iter: &mut T) { + //~^ WARN function cannot return without recursing func(&mut iter.map(|x| x + 1)) + //~^ ERROR reached the type-length limit } diff --git a/tests/ui/recursion/issue-83150.stderr b/tests/ui/recursion/issue-83150.stderr index 783f9cf763254..127de98ddc5b9 100644 --- a/tests/ui/recursion/issue-83150.stderr +++ b/tests/ui/recursion/issue-83150.stderr @@ -1,21 +1,23 @@ warning: function cannot return without recursing - --> $DIR/issue-83150.rs:12:1 + --> $DIR/issue-83150.rs:11:1 | LL | fn func>(iter: &mut T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing +LL | LL | func(&mut iter.map(|x| x + 1)) | ------------------------------ recursive call site | = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>: Iterator` +error: reached the type-length limit while instantiating `<&mut Map<&mut Map<&mut ..., ...>, ...> as Iterator>::map::<..., ...>` + --> $DIR/issue-83150.rs:13:15 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) - = note: required for `&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator` - = note: 65 redundant requirements hidden - = note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>, {closure@$DIR/issue-83150.rs:13:24: 13:27}>` to implement `Iterator` +LL | func(&mut iter.map(|x| x + 1)) + | ^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#![type_length_limit="23068663"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type.txt' error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.rs b/tests/ui/traits/issue-91949-hangs-on-recursion.rs index ddbbcdd052965..d9c422e6f7096 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.rs +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.rs @@ -1,9 +1,5 @@ //@ build-fail //@ compile-flags: -Zinline-mir=no -//@ error-pattern: overflow evaluating the requirement ` as Iterator>::Item == ()` -//@ error-pattern: function cannot return without recursing -//@ normalize-stderr-test: "long-type-\d+" -> "long-type-hash" -//@ ignore-compare-mode-next-solver (hangs) // Regression test for #91949. // This hanged *forever* on 1.56, fixed by #90423. @@ -22,10 +18,12 @@ impl> Iterator for IteratorOfWrapped { } fn recurse(elements: T) -> Vec +//~^ WARN function cannot return without recursing where T: Iterator, { recurse(IteratorOfWrapped(elements).map(|t| t.0)) + //~^ ERROR reached the type-length limit } fn main() { diff --git a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr index c4324f0f0a872..c46c78609d2c3 100644 --- a/tests/ui/traits/issue-91949-hangs-on-recursion.stderr +++ b/tests/ui/traits/issue-91949-hangs-on-recursion.stderr @@ -1,7 +1,8 @@ warning: function cannot return without recursing - --> $DIR/issue-91949-hangs-on-recursion.rs:24:1 + --> $DIR/issue-91949-hangs-on-recursion.rs:20:1 | LL | / fn recurse(elements: T) -> Vec +LL | | LL | | where LL | | T: Iterator, | |___________________________^ cannot return without recursing @@ -12,19 +13,14 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error[E0275]: overflow evaluating the requirement ` as Iterator>::Item == ()` +error: reached the type-length limit while instantiating `, ...>> as Iterator>::map::<..., ...>` + --> $DIR/issue-91949-hangs-on-recursion.rs:25:13 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`) -note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator` - --> $DIR/issue-91949-hangs-on-recursion.rs:17:32 +LL | recurse(IteratorOfWrapped(elements).map(|t| t.0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -LL | impl> Iterator for IteratorOfWrapped { - | -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: 256 redundant requirements hidden - = note: required for `IteratorOfWrapped<(), Map>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>, {closure@$DIR/issue-91949-hangs-on-recursion.rs:28:45: 28:48}>>` to implement `Iterator` + = help: consider adding a `#![type_length_limit="27262965"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type.txt' error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs index c60f1be06c671..d6937481a1551 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/type_length_limit.rs @@ -1,7 +1,6 @@ //@ build-fail -//@ error-pattern: reached the type-length limit while instantiating //@ compile-flags: -Copt-level=0 -//@ normalize-stderr-test: ".nll/" -> "/" +//~^^ ERROR reached the type-length limit // Test that the type length limit can be changed. // The exact type depends on optimizations, so disable them. @@ -31,4 +30,5 @@ pub struct G(std::marker::PhantomData::<(T, K)>); fn main() { drop::>(None); + //~^ ERROR reached the type-length limit } diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/type_length_limit.stderr index 32290a2f5bfc7..83353547d34db 100644 --- a/tests/ui/type_length_limit.stderr +++ b/tests/ui/type_length_limit.stderr @@ -1,8 +1,15 @@ error: reached the type-length limit while instantiating `std::mem::drop::>` - --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + --> $DIR/type_length_limit.rs:32:5 | - = help: consider adding a `#![type_length_limit="10"]` attribute to your crate +LL | drop::>(None); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#![type_length_limit="4010"]` attribute to your crate = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' -error: aborting due to 1 previous error +error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut` + | + = help: consider adding a `#![type_length_limit="10"]` attribute to your crate + +error: aborting due to 2 previous errors From 3273ccea4b2c1995a7ddd059657ded593eb859c9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 1 Jul 2024 16:32:32 -0400 Subject: [PATCH 42/54] Fix spans --- .../rustc_codegen_cranelift/src/abi/mod.rs | 2 +- .../rustc_codegen_cranelift/src/main_shim.rs | 5 ++-- compiler/rustc_codegen_gcc/src/context.rs | 4 ++-- compiler/rustc_codegen_llvm/src/context.rs | 4 ++-- compiler/rustc_codegen_ssa/src/base.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- .../src/const_eval/machine.rs | 2 +- .../src/interpret/terminator.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 21 ++++++++++------ compiler/rustc_monomorphize/src/collector.rs | 24 ++++++------------- .../src/traits/vtable.rs | 3 ++- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 81dfde81e938c..9dc94ab33ea9e 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -376,7 +376,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( ty::ParamEnv::reveal_all(), def_id, fn_args, - Some(source_info.span), + source_info.span, ) .polymorphize(fx.tcx); diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index d1dc147dba8f8..fe0a15514190c 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::AssocKind; use rustc_middle::ty::GenericArg; use rustc_session::config::{sigpipe, EntryFnType}; use rustc_span::symbol::Ident; +use rustc_span::DUMMY_SP; use crate::prelude::*; @@ -119,7 +120,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), report.def_id, tcx.mk_args(&[GenericArg::from(main_ret_ty)]), - None, + DUMMY_SP, ) .polymorphize(tcx); @@ -145,7 +146,7 @@ pub(crate) fn maybe_create_entry_wrapper( ParamEnv::reveal_all(), start_def_id, tcx.mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ) .polymorphize(tcx); let start_func_id = import_function(tcx, m, start_instance); diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 88ffcd7f4b502..1d689c9ac0ef1 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; -use rustc_span::{source_map::respan, Span}; +use rustc_span::{source_map::respan, Span, DUMMY_SP}; use rustc_target::abi::{ call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx, }; @@ -479,7 +479,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), - None, + DUMMY_SP, ); let symbol_name = tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index a012c40ec0a6f..77beb9a6bb386 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -28,7 +28,7 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection}; use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx}; use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; @@ -580,7 +580,7 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { ty::ParamEnv::reveal_all(), def_id, ty::List::empty(), - None, + DUMMY_SP, )), _ => { let name = name.unwrap_or("rust_eh_personality"); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1be4cb186a7e9..137f14fe706cc 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -37,7 +37,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_span::Symbol; +use rustc_span::{Symbol, DUMMY_SP}; use rustc_target::abi::FIRST_VARIANT; use std::cmp; @@ -467,7 +467,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ty::ParamEnv::reveal_all(), start_def_id, cx.tcx().mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ); let start_fn = cx.get_fn_addr(start_instance); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 8b302b59e1312..f5c7821fd7015 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -842,7 +842,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), def_id, args, - Some(fn_span), + fn_span, ) .polymorphize(bx.tcx()), ), diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index cb3288402c11b..17e1d8566c26c 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -253,7 +253,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { ty::ParamEnv::reveal_all(), const_def_id, instance.args, - Some(self.find_closest_untracked_caller_location()), + self.cur_span(), ); return Ok(Some(new_instance)); diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index f59293e7266ac..68acddf63d86e 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -888,6 +888,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.param_env, def_id, instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), + self.cur_span(), ); assert_eq!(fn_inst, concrete_method); } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 65039d8b52c22..3f854ba74916f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -547,8 +547,14 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, - span: Option, + span: Span, ) -> Instance<'tcx> { + // We compute the span lazily, to avoid unnecessary query calls. + // If `span` is a DUMMY_SP, and the def id is local, then use the + // def span of the def id. + let span_or_local_def_span = + || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span }; + match ty::Instance::resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, Ok(None) => { @@ -567,7 +573,7 @@ impl<'tcx> Instance<'tcx> { // We don't use `def_span(def_id)` so that diagnostics point // to the crate root during mono instead of to foreign items. // This is arguably better. - span: span.unwrap_or(DUMMY_SP), + span: span_or_local_def_span(), shrunk, was_written, path, @@ -575,14 +581,14 @@ impl<'tcx> Instance<'tcx> { }); } else { span_bug!( - span.unwrap_or(tcx.def_span(def_id)), + span_or_local_def_span(), "failed to resolve instance for {}", tcx.def_path_str_with_args(def_id, args) ) } } instance => span_bug!( - span.unwrap_or(tcx.def_span(def_id)), + span_or_local_def_span(), "failed to resolve instance for {}: {instance:#?}", tcx.def_path_str_with_args(def_id, args) ), @@ -642,6 +648,7 @@ impl<'tcx> Instance<'tcx> { param_env: ty::ParamEnv<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>, + span: Span, ) -> Instance<'tcx> { debug!("resolve_for_vtable(def_id={:?}, args={:?})", def_id, args); let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); @@ -654,7 +661,7 @@ impl<'tcx> Instance<'tcx> { return Instance { def: InstanceKind::VTableShim(def_id), args }; } - let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, None); + let mut resolved = Instance::expect_resolve(tcx, param_env, def_id, args, span); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); match resolved.def { @@ -731,13 +738,13 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, None) + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f98d4700528d5..342c01ff69731 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -853,13 +853,7 @@ fn visit_fn_use<'tcx>( ) { if let ty::FnDef(def_id, args) = *ty.kind() { let instance = if is_direct_call { - ty::Instance::expect_resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - args, - Some(source), - ) + ty::Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, source) } else { match ty::Instance::resolve_for_fn_ptr(tcx, ty::ParamEnv::reveal_all(), def_id, args) { Some(instance) => instance, @@ -1261,13 +1255,8 @@ fn visit_mentioned_item<'tcx>( match *item { MentionedItem::Fn(ty) => { if let ty::FnDef(def_id, args) = *ty.kind() { - let instance = Instance::expect_resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - args, - Some(span), - ); + let instance = + Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, span); // `visit_instance_use` was written for "used" item collection but works just as well // for "mentioned" item collection. // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway @@ -1492,7 +1481,7 @@ impl<'v> RootCollector<'_, 'v> { ty::ParamEnv::reveal_all(), start_def_id, self.tcx.mk_args(&[main_ret_ty.into()]), - None, + DUMMY_SP, ); self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP)); @@ -1561,9 +1550,10 @@ fn create_mono_items_for_default_impls<'tcx>( } // As mentioned above, the method is legal to eagerly instantiate if it - // only has lifetime generic parameters. This is validated by + // only has lifetime generic parameters. This is validated by calling + // `own_requires_monomorphization` on both the impl and method. let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); - let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, None); + let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index e710b17a10d6e..8f56f9c0f3eea 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -6,7 +6,7 @@ use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry}; use rustc_middle::ty::{GenericArgs, TypeVisitableExt}; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::fmt::Debug; @@ -290,6 +290,7 @@ fn vtable_entries<'tcx>( ty::ParamEnv::reveal_all(), def_id, args, + DUMMY_SP, ); VtblEntry::Method(instance) From a21ba348964e6d72a3369daa4bc22af507eb7778 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 23:01:24 -0400 Subject: [PATCH 43/54] add TyCtxt::as_lang_item, use in new solver --- compiler/rustc_hir/src/lang_items.rs | 13 ++- .../rustc_middle/src/middle/lang_items.rs | 4 + compiler/rustc_middle/src/ty/context.rs | 95 +++++++++++-------- .../src/solve/assembly/mod.rs | 87 +++++++++-------- compiler/rustc_type_ir/src/interner.rs | 2 + 5 files changed, 126 insertions(+), 75 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3c44acb16577a..30c0e40206aaf 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -11,6 +11,7 @@ use crate::def_id::DefId; use crate::{MethodKind, Target}; use rustc_ast as ast; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::symbol::{kw, sym, Symbol}; @@ -23,6 +24,7 @@ pub struct LanguageItems { /// Mappings from lang items to their possibly found [`DefId`]s. /// The index corresponds to the order in [`LangItem`]. items: [Option; std::mem::variant_count::()], + reverse_items: FxIndexMap, /// Lang items that were not found during collection. pub missing: Vec, } @@ -30,7 +32,11 @@ pub struct LanguageItems { impl LanguageItems { /// Construct an empty collection of lang items and no missing ones. pub fn new() -> Self { - Self { items: [None; std::mem::variant_count::()], missing: Vec::new() } + Self { + items: [None; std::mem::variant_count::()], + reverse_items: FxIndexMap::default(), + missing: Vec::new(), + } } pub fn get(&self, item: LangItem) -> Option { @@ -39,6 +45,11 @@ impl LanguageItems { pub fn set(&mut self, item: LangItem, def_id: DefId) { self.items[item as usize] = Some(def_id); + self.reverse_items.insert(def_id, item); + } + + pub fn from_def_id(&self, def_id: DefId) -> Option { + self.reverse_items.get(&def_id).copied() } pub fn iter(&self) -> impl Iterator + '_ { diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index e76d7af6e4aba..a0c9af436e207 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -27,6 +27,10 @@ impl<'tcx> TyCtxt<'tcx> { self.lang_items().get(lang_item) == Some(def_id) } + pub fn as_lang_item(self, def_id: DefId) -> Option { + self.lang_items().from_def_id(def_id) + } + /// Given a [`DefId`] of one of the [`Fn`], [`FnMut`] or [`FnOnce`] traits, /// returns a corresponding [`ty::ClosureKind`]. /// For any other [`DefId`] return `None`. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9225ae6300fc6..155a76713cab6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -366,6 +366,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item)) } + fn as_lang_item(self, def_id: DefId) -> Option { + lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?) + } + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() @@ -584,46 +588,63 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } } -fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { - match lang_item { - TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct, - TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper, - TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars, - TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput, - TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator, - TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture, - TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture, - TraitSolverLangItem::Clone => LangItem::Clone, - TraitSolverLangItem::Copy => LangItem::Copy, - TraitSolverLangItem::Coroutine => LangItem::Coroutine, - TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn, - TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield, - TraitSolverLangItem::Destruct => LangItem::Destruct, - TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind, - TraitSolverLangItem::DynMetadata => LangItem::DynMetadata, - TraitSolverLangItem::EffectsMaybe => LangItem::EffectsMaybe, - TraitSolverLangItem::EffectsIntersection => LangItem::EffectsIntersection, - TraitSolverLangItem::EffectsIntersectionOutput => LangItem::EffectsIntersectionOutput, - TraitSolverLangItem::EffectsNoRuntime => LangItem::EffectsNoRuntime, - TraitSolverLangItem::EffectsRuntime => LangItem::EffectsRuntime, - TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait, - TraitSolverLangItem::FusedIterator => LangItem::FusedIterator, - TraitSolverLangItem::Future => LangItem::Future, - TraitSolverLangItem::FutureOutput => LangItem::FutureOutput, - TraitSolverLangItem::Iterator => LangItem::Iterator, - TraitSolverLangItem::Metadata => LangItem::Metadata, - TraitSolverLangItem::Option => LangItem::Option, - TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait, - TraitSolverLangItem::PointerLike => LangItem::PointerLike, - TraitSolverLangItem::Poll => LangItem::Poll, - TraitSolverLangItem::Sized => LangItem::Sized, - TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait, - TraitSolverLangItem::Tuple => LangItem::Tuple, - TraitSolverLangItem::Unpin => LangItem::Unpin, - TraitSolverLangItem::Unsize => LangItem::Unsize, +macro_rules! bidirectional_lang_item_map { + ($($name:ident),+ $(,)?) => { + fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem { + match lang_item { + $(TraitSolverLangItem::$name => LangItem::$name,)+ + } + } + + fn lang_item_to_trait_lang_item(lang_item: LangItem) -> Option { + Some(match lang_item { + $(LangItem::$name => TraitSolverLangItem::$name,)+ + _ => return None, + }) + } } } +bidirectional_lang_item_map! { +// tidy-alphabetical-start + AsyncDestruct, + AsyncFnKindHelper, + AsyncFnKindUpvars, + AsyncFnOnceOutput, + AsyncIterator, + CallOnceFuture, + CallRefFuture, + Clone, + Copy, + Coroutine, + CoroutineReturn, + CoroutineYield, + Destruct, + DiscriminantKind, + DynMetadata, + EffectsMaybe, + EffectsIntersection, + EffectsIntersectionOutput, + EffectsNoRuntime, + EffectsRuntime, + FnPtrTrait, + FusedIterator, + Future, + FutureOutput, + Iterator, + Metadata, + Option, + PointeeTrait, + PointerLike, + Poll, + Sized, + TransmuteTrait, + Tuple, + Unpin, + Unsize, +// tidy-alphabetical-end +} + impl<'tcx> rustc_type_ir::inherent::DefId> for DefId { fn as_local(self) -> Option { self.as_local() diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 6ee684605ac60..20a0da16c7521 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -387,48 +387,61 @@ where G::consider_auto_trait_candidate(self, goal) } else if cx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { - G::consider_builtin_sized_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) - || cx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) - { - G::consider_builtin_copy_clone_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { - G::consider_builtin_pointer_like_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { - G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { - G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { - G::consider_builtin_tuple_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { - G::consider_builtin_pointee_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { - G::consider_builtin_future_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { - G::consider_builtin_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { - G::consider_builtin_fused_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { - G::consider_builtin_async_iterator_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { - G::consider_builtin_coroutine_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { - G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { - G::consider_builtin_async_destruct_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { - G::consider_builtin_destruct_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { - G::consider_builtin_transmute_candidate(self, goal) - } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::EffectsIntersection) { - G::consider_builtin_effects_intersection_candidate(self, goal) } else { - Err(NoSolution) + match cx.as_lang_item(trait_def_id) { + Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal), + Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { + G::consider_builtin_copy_clone_candidate(self, goal) + } + Some(TraitSolverLangItem::PointerLike) => { + G::consider_builtin_pointer_like_candidate(self, goal) + } + Some(TraitSolverLangItem::FnPtrTrait) => { + G::consider_builtin_fn_ptr_trait_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncFnKindHelper) => { + G::consider_builtin_async_fn_kind_helper_candidate(self, goal) + } + Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal), + Some(TraitSolverLangItem::PointeeTrait) => { + G::consider_builtin_pointee_candidate(self, goal) + } + Some(TraitSolverLangItem::Future) => { + G::consider_builtin_future_candidate(self, goal) + } + Some(TraitSolverLangItem::Iterator) => { + G::consider_builtin_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::FusedIterator) => { + G::consider_builtin_fused_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncIterator) => { + G::consider_builtin_async_iterator_candidate(self, goal) + } + Some(TraitSolverLangItem::Coroutine) => { + G::consider_builtin_coroutine_candidate(self, goal) + } + Some(TraitSolverLangItem::DiscriminantKind) => { + G::consider_builtin_discriminant_kind_candidate(self, goal) + } + Some(TraitSolverLangItem::AsyncDestruct) => { + G::consider_builtin_async_destruct_candidate(self, goal) + } + Some(TraitSolverLangItem::Destruct) => { + G::consider_builtin_destruct_candidate(self, goal) + } + Some(TraitSolverLangItem::TransmuteTrait) => { + G::consider_builtin_transmute_candidate(self, goal) + } + Some(TraitSolverLangItem::EffectsIntersection) => { + G::consider_builtin_effects_intersection_candidate(self, goal) + } + _ => Err(NoSolution), + } }; candidates.extend(result); diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6665158c7cd34..84c7e6e8f2003 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -220,6 +220,8 @@ pub trait Interner: fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool; + fn as_lang_item(self, def_id: Self::DefId) -> Option; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; // FIXME: move `fast_reject` into `rustc_type_ir`. From 5a837515f28eed106dd031b0243d6476eba58dd9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 29 Jun 2024 23:05:35 -0400 Subject: [PATCH 44/54] Make fn traits into first-class TraitSolverLangItems to avoid needing fn_trait_kind_from_def_id --- compiler/rustc_middle/src/ty/context.rs | 16 +++++----- .../src/solve/assembly/mod.rs | 30 ++++++++++++++++--- compiler/rustc_type_ir/src/interner.rs | 4 --- compiler/rustc_type_ir/src/lang_items.rs | 6 ++++ 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 155a76713cab6..7c3d2df72faa2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -537,14 +537,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(trait_def_id).implement_via_object } - fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { - self.fn_trait_kind_from_def_id(trait_def_id) - } - - fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { - self.async_fn_trait_kind_from_def_id(trait_def_id) - } - fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator { self.supertrait_def_ids(trait_def_id) } @@ -608,8 +600,11 @@ macro_rules! bidirectional_lang_item_map { bidirectional_lang_item_map! { // tidy-alphabetical-start AsyncDestruct, + AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnMut, + AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, CallOnceFuture, @@ -622,11 +617,14 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, - EffectsMaybe, EffectsIntersection, EffectsIntersectionOutput, + EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + Fn, + FnMut, + FnOnce, FnPtrTrait, FusedIterator, Future, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 20a0da16c7521..38a4f7dfe25cb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -387,16 +387,38 @@ where G::consider_auto_trait_candidate(self, goal) } else if cx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { - G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { - G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else { match cx.as_lang_item(trait_def_id) { Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal), Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => { G::consider_builtin_copy_clone_candidate(self, goal) } + Some(TraitSolverLangItem::Fn) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn) + } + Some(TraitSolverLangItem::FnMut) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut) + } + Some(TraitSolverLangItem::FnOnce) => { + G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce) + } + Some(TraitSolverLangItem::AsyncFn) => { + G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn) + } + Some(TraitSolverLangItem::AsyncFnMut) => { + G::consider_builtin_async_fn_trait_candidates( + self, + goal, + ty::ClosureKind::FnMut, + ) + } + Some(TraitSolverLangItem::AsyncFnOnce) => { + G::consider_builtin_async_fn_trait_candidates( + self, + goal, + ty::ClosureKind::FnOnce, + ) + } Some(TraitSolverLangItem::PointerLike) => { G::consider_builtin_pointer_like_candidate(self, goal) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 84c7e6e8f2003..f76a2f55c482e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -254,10 +254,6 @@ pub trait Interner: fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; - fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; - - fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; - fn supertrait_def_ids(self, trait_def_id: Self::DefId) -> impl IntoIterator; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index cf00c37caa287..265a411882735 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -3,8 +3,11 @@ pub enum TraitSolverLangItem { // tidy-alphabetical-start AsyncDestruct, + AsyncFn, AsyncFnKindHelper, AsyncFnKindUpvars, + AsyncFnMut, + AsyncFnOnce, AsyncFnOnceOutput, AsyncIterator, CallOnceFuture, @@ -22,6 +25,9 @@ pub enum TraitSolverLangItem { EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + Fn, + FnMut, + FnOnce, FnPtrTrait, FusedIterator, Future, From b1059ccda210e11c19b3c639a13ddd64de781daf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 2 Jul 2024 15:55:17 -0400 Subject: [PATCH 45/54] Instance::resolve -> Instance::try_resolve, and other nits --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 2 +- .../src/check_consts/check.rs | 2 +- .../src/interpret/eval_context.rs | 2 +- .../nice_region_error/static_impl_trait.rs | 2 +- compiler/rustc_lint/src/internal.rs | 4 ++-- compiler/rustc_lint/src/noop_method_call.rs | 4 +++- .../rustc_middle/src/mir/interpret/queries.rs | 4 ++-- compiler/rustc_middle/src/ty/instance.rs | 22 ++++++++++++++----- compiler/rustc_middle/src/util/call_kind.rs | 2 +- compiler/rustc_mir_build/src/lints.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 3 ++- compiler/rustc_mir_transform/src/inline.rs | 2 +- .../rustc_mir_transform/src/inline/cycle.rs | 2 +- compiler/rustc_passes/src/abi_test.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 2 +- .../clippy_lints/src/assigning_clones.rs | 4 ++-- .../clippy/clippy_lints/src/non_copy_const.rs | 2 +- src/tools/miri/src/eval.rs | 2 +- tests/ui/codegen/overflow-during-mono.rs | 1 + tests/ui/codegen/overflow-during-mono.stderr | 2 +- .../issue-58952-filter-type-length.rs | 1 + 22 files changed, 44 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 44ab762f66e0a..7ef53fa2078e4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3733,7 +3733,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { if tcx.is_diagnostic_item(sym::deref_method, method_did) { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, self.param_env, deref_target, method_args) + Instance::try_resolve(tcx, self.param_env, deref_target, method_args) .transpose() }); if let Some(Ok(instance)) = deref_target { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index fba18c381466b..e1df5a8ec1655 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -948,7 +948,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { return; } - if let Ok(Some(instance)) = ty::Instance::resolve( + if let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, self.param_env, *fn_did, diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ab60cc3792098..0d8a17775dd3d 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -768,7 +768,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { is_trait = true; if let Ok(Some(instance)) = - Instance::resolve(tcx, param_env, callee, fn_args) + Instance::try_resolve(tcx, param_env, callee, fn_args) && let InstanceKind::Item(def) = instance.def { // Resolve a trait method call to its concrete implementation, which may be in a diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 67eeb1b3b8712..830c4bd3e26e0 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -618,7 +618,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("resolve: {:?}, {:#?}", def, args); trace!("param_env: {:#?}", self.param_env); trace!("args: {:#?}", args); - match ty::Instance::resolve(*self.tcx, self.param_env, def, args) { + match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { Ok(Some(instance)) => Ok(instance), Ok(None) => throw_inval!(TooGeneric), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 71a86683c2123..9973646aecd6a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -534,7 +534,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let tcx = self.tcx(); // Find the method being called. - let Ok(Some(instance)) = ty::Instance::resolve( + let Ok(Some(instance)) = ty::Instance::try_resolve( tcx, ctxt.param_env, ctxt.assoc_item.def_id, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 9110cccdc46f0..772cc2ff8b997 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -88,7 +88,7 @@ declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]); impl LateLintPass<'_> for QueryStability { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Some((span, def_id, args)) = typeck_results_of_method_fn(cx, expr) else { return }; - if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, args) { + if let Ok(Some(instance)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, args) { let def_id = instance.def_id(); if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) { cx.emit_span_lint( @@ -393,7 +393,7 @@ impl LateLintPass<'_> for Diagnostics { }; // Is the callee marked with `#[rustc_lint_diagnostics]`? - let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, fn_gen_args) + let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args) .ok() .flatten() .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics)); diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 91441248e70fd..307e4bebe9a1b 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -96,7 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { .tcx .normalize_erasing_regions(cx.param_env, cx.typeck_results().node_args(expr.hir_id)); // Resolve the trait method instance. - let Ok(Some(i)) = ty::Instance::resolve(cx.tcx, cx.param_env, did, args) else { return }; + let Ok(Some(i)) = ty::Instance::try_resolve(cx.tcx, cx.param_env, did, args) else { + return; + }; // (Re)check that it implements the noop diagnostic. let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return }; if !matches!( diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 95857e8579d9a..96613592bbcce 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -73,7 +73,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve( + match ty::Instance::try_resolve( self, param_env, // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? ct.def, ct.args, @@ -106,7 +106,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve(self, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(self, param_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 3f854ba74916f..ae54411d788ab 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -516,7 +516,7 @@ impl<'tcx> Instance<'tcx> { /// from `Ok(None)` to avoid misleading diagnostics when an error /// has already been/will be emitted, for the original cause #[instrument(level = "debug", skip(tcx), ret)] - pub fn resolve( + pub fn try_resolve( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, def_id: DefId, @@ -555,7 +555,7 @@ impl<'tcx> Instance<'tcx> { let span_or_local_def_span = || if span.is_dummy() && def_id.is_local() { tcx.def_span(def_id) } else { span }; - match ty::Instance::resolve(tcx, param_env, def_id, args) { + match ty::Instance::try_resolve(tcx, param_env, def_id, args) { Ok(Some(instance)) => instance, Ok(None) => { let type_length = type_length(args); @@ -605,7 +605,7 @@ impl<'tcx> Instance<'tcx> { // Use either `resolve_closure` or `resolve_for_vtable` assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); - Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { + Instance::try_resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); @@ -738,13 +738,25 @@ impl<'tcx> Instance<'tcx> { pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) + Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), + ) } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); let args = tcx.mk_args(&[ty.into()]); - Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args, DUMMY_SP) + Instance::expect_resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + args, + ty.ty_adt_def().and_then(|adt| tcx.hir().span_if_local(adt.did())).unwrap_or(DUMMY_SP), + ) } #[instrument(level = "debug", skip(tcx), ret)] diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs index dc1d73684f4f2..0815c291173de 100644 --- a/compiler/rustc_middle/src/util/call_kind.rs +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -98,7 +98,7 @@ pub fn call_kind<'tcx>( Some(CallKind::Operator { self_arg, trait_id, self_ty: method_args.type_at(0) }) } else if is_deref { let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, param_env, deref_target, method_args).transpose() + Instance::try_resolve(tcx, param_env, deref_target, method_args).transpose() }); if let Some(Ok(instance)) = deref_target { let deref_target_ty = instance.ty(tcx, param_env); diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 2c817d605af2a..1c7aa9f9ed095 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -141,7 +141,7 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> { return false; }; let (callee, call_args) = if let Ok(Some(instance)) = - Instance::resolve(tcx, param_env, callee, normalized_args) + Instance::try_resolve(tcx, param_env, callee, normalized_args) { (instance.def_id(), instance.args) } else { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 93db1f618533b..fd778ef78a3ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -558,7 +558,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self .tcx .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id)); - let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, args) { + let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args) + { Ok(Some(i)) => i, Ok(None) => { // It should be assoc consts if there's no error but we cannot resolve it. diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 6fa31c1174d0b..5075e0727548f 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -389,7 +389,7 @@ impl<'tcx> Inliner<'tcx> { // To resolve an instance its args have to be fully normalized. let args = self.tcx.try_normalize_erasing_regions(self.param_env, args).ok()?; let callee = - Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; + Instance::try_resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { return None; diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 35bcd24ce95ba..d4477563e3adb 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -53,7 +53,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( trace!(?caller, ?param_env, ?args, "cannot normalize, skipping"); continue; }; - let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, args) else { + let Ok(Some(callee)) = ty::Instance::try_resolve(tcx, param_env, callee, args) else { trace!(?callee, "cannot resolve, skipping"); continue; }; diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs index 0c3dd649997ef..839b96fb3de84 100644 --- a/compiler/rustc_passes/src/abi_test.rs +++ b/compiler/rustc_passes/src/abi_test.rs @@ -61,7 +61,7 @@ fn unwrap_fn_abi<'tcx>( fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { let param_env = tcx.param_env(item_def_id); let args = GenericArgs::identity_for_item(tcx, item_def_id); - let instance = match Instance::resolve(tcx, param_env, item_def_id.into(), args) { + let instance = match Instance::try_resolve(tcx, param_env, item_def_id.into(), args) { Ok(Some(instance)) => instance, Ok(None) => { // Not sure what to do here, but `LayoutError::Unknown` seems reasonable? diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 4eefd0eb17c40..b0ced8e920fe5 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -629,7 +629,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); let args_ref = args.internal(&mut *tables, tcx); - match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + match Instance::try_resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { Ok(Some(instance)) => Some(instance.stable(&mut *tables)), Ok(None) | Err(_) => None, } diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 05ea74b0d534f..406f38f411ecd 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -103,7 +103,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< let args = cx.typeck_results().node_args(expr.hir_id); // If we could not resolve the method, don't apply the lint - let Ok(Some(resolved_method)) = Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args) else { + let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else { return None; }; if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone { @@ -119,7 +119,7 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option< // If we could not resolve the method, don't apply the lint let Ok(Some(resolved_method)) = (match kind { - ty::FnDef(_, args) => Instance::resolve(cx.tcx, cx.param_env, fn_def_id, args), + ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args), _ => Ok(None), }) else { return None; 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 5cb8e7bfab2a9..b71ebe35eb6a8 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -293,7 +293,7 @@ impl<'tcx> NonCopyConst<'tcx> { ct: ty::UnevaluatedConst<'tcx>, span: Span, ) -> EvalToValTreeResult<'tcx> { - match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) { + match ty::Instance::try_resolve(tcx, param_env, ct.def, ct.args) { Ok(Some(instance)) => { let cid = GlobalId { instance, diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index c0827cce26301..9142b8b5fdbc0 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -375,7 +375,7 @@ pub fn create_ecx<'tcx>( }); let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( + let start_instance = ty::Instance::try_resolve( tcx, ty::ParamEnv::reveal_all(), start_id, diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs index 278298f27ff0e..4d3f2c18dc837 100644 --- a/tests/ui/codegen/overflow-during-mono.rs +++ b/tests/ui/codegen/overflow-during-mono.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ error-pattern: reached the type-length limit while instantiating #![recursion_limit = "32"] diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr index 9e463378004dc..e06fcd289669f 100644 --- a/tests/ui/codegen/overflow-during-mono.stderr +++ b/tests/ui/codegen/overflow-during-mono.stderr @@ -1,4 +1,4 @@ -error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:12:41: 12:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` +error: reached the type-length limit while instantiating `, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>, ...> as Iterator>::try_fold::<..., ..., ...>` --> $SRC_DIR/core/src/iter/adapters/filter.rs:LL:COL | = help: consider adding a `#![type_length_limit="20156994"]` attribute to your crate diff --git a/tests/ui/iterators/issue-58952-filter-type-length.rs b/tests/ui/iterators/issue-58952-filter-type-length.rs index b2c208ae28f19..4f3ddce69d822 100644 --- a/tests/ui/iterators/issue-58952-filter-type-length.rs +++ b/tests/ui/iterators/issue-58952-filter-type-length.rs @@ -1,4 +1,5 @@ //@ build-fail +//@ error-pattern: reached the type-length limit while instantiating //! This snippet causes the type length to blowup exponentially, //! so check that we don't accidentally exceed the type length limit. From 9f32459c988dec799458f304bbc49ed5dc6ef772 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 Jul 2024 06:15:17 +0800 Subject: [PATCH 46/54] Fix incorrect suggestion for extra argument with a type error --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 26 ++++ .../suggest-better-removing-issue-126246.rs | 21 +++ ...uggest-better-removing-issue-126246.stderr | 124 ++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs create mode 100644 tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 63148ab517c5d..c6d72700b3fce 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -951,6 +951,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return err.emit(); } + // Special case, we found an extra argument is provided, which is very common in practice. + // but there is a obviously better removing suggestion compared to the current one, + // try to find the argument with Error type, if we removed it all the types will become good, + // then we will replace the current suggestion. + if let [Error::Extra(provided_idx)] = &errors[..] { + let remove_idx_is_perfect = |idx: usize| -> bool { + let removed_arg_tys = provided_arg_tys + .iter() + .enumerate() + .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) + .collect::>(); + std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( + |((expected_ty, _), (provided_ty, _))| { + !provided_ty.references_error() + && self.can_coerce(*provided_ty, *expected_ty) + }, + ) + }; + + if !remove_idx_is_perfect(provided_idx.as_usize()) { + if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) { + errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; + } + } + } + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { struct_span_code_err!( self.dcx(), diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs new file mode 100644 index 0000000000000..fa1802283c39c --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.rs @@ -0,0 +1,21 @@ +fn add_one(x: i32) -> i32 { + x + 1 +} + +fn add_two(x: i32, y: i32) -> i32 { + x + y +} + +fn main() { + add_one(2, 2); //~ ERROR this function takes 1 argument but 2 arguments were supplied + add_one(no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_one(10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 1 argument but 2 arguments were supplied + add_two(10, no_such_local, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(no_such_local, 10, 10); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied + add_two(10, 10, no_such_local); //~ ERROR cannot find value `no_such_local` in this scope + //~| ERROR this function takes 2 arguments but 3 arguments were supplied +} diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr new file mode 100644 index 0000000000000..7c4daa3ffe95b --- /dev/null +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr @@ -0,0 +1,124 @@ +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:11:13 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:13:17 + | +LL | add_one(10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:15:17 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:17:13 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find value `no_such_local` in this scope + --> $DIR/suggest-better-removing-issue-126246.rs:19:21 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^^^^^^^ not found in this scope + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:10:5 + | +LL | add_one(2, 2); + | ^^^^^^^ --- + | | | + | | unexpected argument of type `{integer}` + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:11:5 + | +LL | add_one(no_such_local, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:13:5 + | +LL | add_one(10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:1:4 + | +LL | fn add_one(x: i32) -> i32 { + | ^^^^^^^ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:15:5 + | +LL | add_two(10, no_such_local, 10); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:17:5 + | +LL | add_two(no_such_local, 10, 10); + | ^^^^^^^ --------------- + | | + | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error[E0061]: this function takes 2 arguments but 3 arguments were supplied + --> $DIR/suggest-better-removing-issue-126246.rs:19:5 + | +LL | add_two(10, 10, no_such_local); + | ^^^^^^^ --------------- + | | | + | | unexpected argument + | help: remove the extra argument + | +note: function defined here + --> $DIR/suggest-better-removing-issue-126246.rs:5:4 + | +LL | fn add_two(x: i32, y: i32) -> i32 { + | ^^^^^^^ ------ ------ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0061, E0425. +For more information about an error, try `rustc --explain E0061`. From 64a3bd84d83a6138b6e7db82a53199246f292e53 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:01:15 -0500 Subject: [PATCH 47/54] Always preserve user-written comments in assembly --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 3 ++- tests/assembly/asm-comments.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/assembly/asm-comments.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index c4cfc0b6dc6a1..a868c56c4e625 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -436,7 +436,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Options.MCOptions.AsmVerbose = AsmComments; - Options.MCOptions.PreserveAsmComments = AsmComments; + // Always preserve comments that were written by the user + Options.MCOptions.PreserveAsmComments = true; Options.MCOptions.ABIName = ABIStr; if (SplitDwarfFile) { Options.MCOptions.SplitDwarfFile = SplitDwarfFile; diff --git a/tests/assembly/asm-comments.rs b/tests/assembly/asm-comments.rs new file mode 100644 index 0000000000000..557009975ddc9 --- /dev/null +++ b/tests/assembly/asm-comments.rs @@ -0,0 +1,12 @@ +//@ assembly-output: emit-asm +//@ only-x86_64 +// Check that comments in assembly get passed + +#![crate_type = "lib"] + +// CHECK-LABEL: test_comments: +#[no_mangle] +pub fn test_comments() { + // CHECK: example comment + unsafe { core::arch::asm!("nop // example comment") }; +} From c15a698f567356cea22e79686c2883f3557bae0b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:08:49 -0500 Subject: [PATCH 48/54] Rename the `asm-comments` compiler flag to `verbose-asm` Since this codegen flag now only controls LLVM-generated comments rather than all assembly comments, make the name more accurate (and also match Clang). --- compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs | 4 ++-- compiler/rustc_codegen_llvm/src/back/write.rs | 4 ++-- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 4 ++-- compiler/rustc_session/src/options.rs | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index 28a88dd2efea0..b72636a62248e 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -32,7 +32,7 @@ impl OwnedTargetMachine { unique_section_names: bool, trap_unreachable: bool, singletree: bool, - asm_comments: bool, + verbose_asm: bool, emit_stack_size_section: bool, relax_elf_relocations: bool, use_init_array: bool, @@ -64,7 +64,7 @@ impl OwnedTargetMachine { unique_section_names, trap_unreachable, singletree, - asm_comments, + verbose_asm, emit_stack_size_section, relax_elf_relocations, use_init_array, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 5e481eb98f55f..2fda19bf0c914 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -214,7 +214,7 @@ pub fn target_machine_factory( sess.opts.unstable_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.unstable_opts.emit_stack_sizes; - let asm_comments = sess.opts.unstable_opts.asm_comments; + let verbose_asm = sess.opts.unstable_opts.verbose_asm; let relax_elf_relocations = sess.opts.unstable_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations); @@ -289,7 +289,7 @@ pub fn target_machine_factory( funique_section_names, trap_unreachable, singlethread, - asm_comments, + verbose_asm, emit_stack_size_section, relax_elf_relocations, use_init_array, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 132e1f9e8fd93..08e9e312827ce 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2185,7 +2185,7 @@ extern "C" { UniqueSectionNames: bool, TrapUnreachable: bool, Singlethread: bool, - AsmComments: bool, + VerboseAsm: bool, EmitStackSizeSection: bool, RelaxELFRelocations: bool, UseInitArray: bool, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9bd67a1154b7d..e2ba75dfd1902 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -757,7 +757,6 @@ fn test_unstable_options_tracking_hash() { // tidy-alphabetical-start tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); - tracked!(asm_comments, true); tracked!(assume_incomplete_release, true); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); @@ -862,6 +861,7 @@ fn test_unstable_options_tracking_hash() { tracked!(uninit_const_chunk_threshold, 123); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); + tracked!(verbose_asm, true); tracked!(verify_llvm_ir, true); tracked!(virtual_function_elimination, true); tracked!(wasi_exec_model, Some(WasiExecModel::Reactor)); diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index a868c56c4e625..283c4fbbb7cf4 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -407,7 +407,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( const char *ABIStr, LLVMRustCodeModel RustCM, LLVMRustRelocModel RustReloc, LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat, bool FunctionSections, bool DataSections, bool UniqueSectionNames, - bool TrapUnreachable, bool Singlethread, bool AsmComments, + bool TrapUnreachable, bool Singlethread, bool VerboseAsm, bool EmitStackSizeSection, bool RelaxELFRelocations, bool UseInitArray, const char *SplitDwarfFile, const char *OutputObjFile, const char *DebugInfoCompression, bool UseEmulatedTls, @@ -435,7 +435,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; - Options.MCOptions.AsmVerbose = AsmComments; + Options.MCOptions.AsmVerbose = VerboseAsm; // Always preserve comments that were written by the user Options.MCOptions.PreserveAsmComments = true; Options.MCOptions.ABIName = ABIStr; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 2e4421d50e313..7421cae65e4f8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1630,8 +1630,6 @@ options! { "only allow the listed language features to be enabled in code (comma separated)"), always_encode_mir: bool = (false, parse_bool, [TRACKED], "encode MIR of all functions into the crate metadata (default: no)"), - asm_comments: bool = (false, parse_bool, [TRACKED], - "generate comments into the assembly (may change behavior) (default: no)"), assert_incr_state: Option = (None, parse_opt_string, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), @@ -2107,6 +2105,8 @@ written to standard error output)"), "Generate sync unwind tables instead of async unwind tables (default: no)"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), + verbose_asm: bool = (false, parse_bool, [TRACKED], + "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"), #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")] verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH], "in general, enable more debug printouts (default: no)"), From 1a6893e14b7d08aee18acf82b9a08e1ba8534d7b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 21 Jun 2024 14:17:47 -0500 Subject: [PATCH 49/54] Add documentation for -Zverbose-asm --- .../src/compiler-flags/verbose-asm.md | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/verbose-asm.md diff --git a/src/doc/unstable-book/src/compiler-flags/verbose-asm.md b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md new file mode 100644 index 0000000000000..84eb90a14cf53 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/verbose-asm.md @@ -0,0 +1,70 @@ +# `verbose-asm` + +The tracking issue for this feature is: [#126802](https://github.com/rust-lang/rust/issues/126802). + +------------------------ + +This enables passing `-Zverbose-asm` to get contextual comments added by LLVM. + +Sample code: + +```rust +#[no_mangle] +pub fn foo(a: i32, b: i32) -> i32 { + a + b +} +``` + +Default output: + +```asm +foo: + push rax + add edi, esi + mov dword ptr [rsp + 4], edi + seto al + jo .LBB0_2 + mov eax, dword ptr [rsp + 4] + pop rcx + ret +.LBB0_2: + lea rdi, [rip + .L__unnamed_1] + mov rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL] + call rax + +.L__unnamed_2: + .ascii "/app/example.rs" + +.L__unnamed_1: + .quad .L__unnamed_2 + .asciz "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000" +``` + +With `-Zverbose-asm`: + +```asm +foo: # @foo +# %bb.0: + push rax + add edi, esi + mov dword ptr [rsp + 4], edi # 4-byte Spill + seto al + jo .LBB0_2 +# %bb.1: + mov eax, dword ptr [rsp + 4] # 4-byte Reload + pop rcx + ret +.LBB0_2: + lea rdi, [rip + .L__unnamed_1] + mov rax, qword ptr [rip + core::panicking::panic_const::panic_const_add_overflow::h9c85248fe0d735b2@GOTPCREL] + call rax + # -- End function +.L__unnamed_2: + .ascii "/app/example.rs" + +.L__unnamed_1: + .quad .L__unnamed_2 + .asciz "\017\000\000\000\000\000\000\000\004\000\000\000\005\000\000" + + # DW_AT_external +``` From 9e71c7b5a98fb1f18eade36c9188467616550ffc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 3 Jul 2024 11:34:39 +0200 Subject: [PATCH 50/54] Small `run-make-support` API improvements --- src/tools/run-make-support/src/lib.rs | 6 ++++-- src/tools/run-make-support/src/rustc.rs | 3 ++- tests/run-make/emit-named-files/rmake.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 294dae109425f..9a180fe4ad19a 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -321,8 +321,9 @@ pub fn set_host_rpath(cmd: &mut Command) { /// Read the contents of a file that cannot simply be read by /// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. #[track_caller] -pub fn invalid_utf8_contains>(path: P, expected: &str) { +pub fn invalid_utf8_contains, S: AsRef>(path: P, expected: S) { let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); if !String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); eprintln!("{}", String::from_utf8_lossy(&buffer)); @@ -335,8 +336,9 @@ pub fn invalid_utf8_contains>(path: P, expected: &str) { /// Read the contents of a file that cannot simply be read by /// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. #[track_caller] -pub fn invalid_utf8_not_contains>(path: P, expected: &str) { +pub fn invalid_utf8_not_contains, S: AsRef>(path: P, expected: S) { let buffer = fs_wrapper::read(path.as_ref()); + let expected = expected.as_ref(); if String::from_utf8_lossy(&buffer).contains(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); eprintln!("{}", String::from_utf8_lossy(&buffer)); diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 3f23c1b8f9e76..054836e87cfbc 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -86,7 +86,8 @@ impl Rustc { } /// Specify type(s) of output files to generate. - pub fn emit(&mut self, kinds: &str) -> &mut Self { + pub fn emit>(&mut self, kinds: S) -> &mut Self { + let kinds = kinds.as_ref(); self.cmd.arg(format!("--emit={kinds}")); self } diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index 79c3ee90c9875..a02c97fec4cba 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{fs_wrapper, rustc}; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); - rustc().input("foo.rs").emit(&format!("{format}={}", out_file.display())).run(); + rustc().input("foo.rs").emit(format!("{format}={}", out_file.display())).run(); assert!(out_file.is_file()); } From bcbcbfff4452ca34c4cee6a7737141df39591668 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 3 Jul 2024 14:23:09 +0300 Subject: [PATCH 51/54] bootstrap: pass correct struct size to winapi --- src/bootstrap/src/bin/rustc.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 009e62469b4d1..46e845f77ae1b 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -317,9 +317,7 @@ fn format_rusage_data(child: Child) -> Option { use windows::{ Win32::Foundation::HANDLE, - Win32::System::ProcessStatus::{ - K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, - }, + Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, Win32::System::Threading::GetProcessTimes, Win32::System::Time::FileTimeToSystemTime, }; @@ -331,6 +329,7 @@ fn format_rusage_data(child: Child) -> Option { let mut kernel_filetime = Default::default(); let mut kernel_time = Default::default(); let mut memory_counters = PROCESS_MEMORY_COUNTERS::default(); + let memory_counters_size = std::mem::size_of_val(&memory_counters); unsafe { GetProcessTimes( @@ -347,15 +346,9 @@ fn format_rusage_data(child: Child) -> Option { // Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process // with the given handle and none of that process's children. - unsafe { - K32GetProcessMemoryInfo( - handle, - &mut memory_counters, - std::mem::size_of::() as u32, - ) - } - .ok() - .ok()?; + unsafe { K32GetProcessMemoryInfo(handle, &mut memory_counters, memory_counters_size as u32) } + .ok() + .ok()?; // Guide on interpreting these numbers: // https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information From 8b6435d5ce4efaecca51e530f0cb3c44d527f3c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 2 Jul 2024 17:35:49 -0300 Subject: [PATCH 52/54] Add parse fail test using safe trait/impl trait --- .../unsafe-extern-blocks/safe-impl-trait.gated.stderr | 8 ++++++++ .../ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs | 8 ++++++++ .../unsafe-extern-blocks/safe-impl-trait.ungated.stderr | 8 ++++++++ .../unsafe-extern-blocks/safe-trait.gated.stderr | 8 ++++++++ tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs | 7 +++++++ .../unsafe-extern-blocks/safe-trait.ungated.stderr | 8 ++++++++ 6 files changed, 47 insertions(+) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr new file mode 100644 index 0000000000000..80e7a45f57e79 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.gated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `impl` + --> $DIR/safe-impl-trait.rs:5:6 + | +LL | safe impl Bar for () { } + | ^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs new file mode 100644 index 0000000000000..57c03e4d896be --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.rs @@ -0,0 +1,8 @@ +//@ revisions: gated ungated +#![cfg_attr(gated, feature(unsafe_extern_blocks))] + +trait Bar {} +safe impl Bar for () { } +//~^ ERROR expected one of `!` or `::`, found keyword `impl` + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr new file mode 100644 index 0000000000000..80e7a45f57e79 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-impl-trait.ungated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `impl` + --> $DIR/safe-impl-trait.rs:5:6 + | +LL | safe impl Bar for () { } + | ^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr new file mode 100644 index 0000000000000..de84037f28c58 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.gated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `trait` + --> $DIR/safe-trait.rs:4:6 + | +LL | safe trait Foo {} + | ^^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs new file mode 100644 index 0000000000000..e73cb45b18877 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.rs @@ -0,0 +1,7 @@ +//@ revisions: gated ungated +#![cfg_attr(gated, feature(unsafe_extern_blocks))] + +safe trait Foo {} +//~^ ERROR expected one of `!` or `::`, found keyword `trait` + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr new file mode 100644 index 0000000000000..de84037f28c58 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-trait.ungated.stderr @@ -0,0 +1,8 @@ +error: expected one of `!` or `::`, found keyword `trait` + --> $DIR/safe-trait.rs:4:6 + | +LL | safe trait Foo {} + | ^^^^^ expected one of `!` or `::` + +error: aborting due to 1 previous error + From 403e2e2bbd4c3ae3460ab0d922cdb0fae15725a7 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 3 Jul 2024 10:12:39 -0700 Subject: [PATCH 53/54] Disable rmake test rustdoc-io-error on riscv64gc-gnu --- tests/run-make/inaccessible-temp-dir/rmake.rs | 2 +- tests/run-make/rustdoc-io-error/rmake.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index b98e151e90696..62b8479c32881 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -14,7 +14,7 @@ // See https://github.com/rust-lang/rust/issues/66530 //@ ignore-riscv64 -// FIXME: The riscv build container runs as root, and can always write +// FIXME: The riscv64gc-gnu build container runs as root, and can always write // into `inaccessible/tmp`. Ideally, the riscv64-gnu docker container // would use a non-root user, but this leads to issues with // `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs index d60e4438e6f27..69afea401622d 100644 --- a/tests/run-make/rustdoc-io-error/rmake.rs +++ b/tests/run-make/rustdoc-io-error/rmake.rs @@ -6,8 +6,13 @@ // permissions so that it is not writable. We have to take special care to set // the permissions back to normal so that it's able to be deleted later. +//@ ignore-riscv64 +//@ ignore-arm +// FIXME: The riscv64gc-gnu and armhf-gnu build containers run as root, +// and can always write into `inaccessible/tmp`. Ideally, these docker +// containers would use a non-root user, but this leads to issues with +// `mkfs.ext4 -d`, as well as mounting a loop device for the rootfs. //@ ignore-windows - the `set_readonly` functions doesn't work on folders. -//@ ignore-arm - weird file perms on armhf-gnu use run_make_support::{path, rustdoc}; use std::fs; From 493093796014201f8b519324d45f00c8b2e7f2b2 Mon Sep 17 00:00:00 2001 From: Liu Dingming Date: Thu, 4 Jul 2024 04:41:37 +0800 Subject: [PATCH 54/54] Less magic number for corountine --- compiler/rustc_middle/src/ty/sty.rs | 6 +++++- compiler/rustc_mir_transform/src/coroutine.rs | 7 ++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ff40a726fbc38..52690ae678d6c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -68,6 +68,10 @@ impl<'tcx> ty::CoroutineArgs> { const RETURNED: usize = 1; /// Coroutine has been poisoned. const POISONED: usize = 2; + /// Number of variants to reserve in coroutine state. Corresponds to + /// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED` + /// (end of a coroutine) states. + const RESERVED_VARIANTS: usize = 3; const UNRESUMED_NAME: &'static str = "Unresumed"; const RETURNED_NAME: &'static str = "Returned"; @@ -116,7 +120,7 @@ impl<'tcx> ty::CoroutineArgs> { Self::UNRESUMED => Cow::from(Self::UNRESUMED_NAME), Self::RETURNED => Cow::from(Self::RETURNED_NAME), Self::POISONED => Cow::from(Self::POISONED_NAME), - _ => Cow::from(format!("Suspend{}", v.as_usize() - 3)), + _ => Cow::from(format!("Suspend{}", v.as_usize() - Self::RESERVED_VARIANTS)), } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 05674792426f1..4c00038365b73 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -208,11 +208,8 @@ const UNRESUMED: usize = CoroutineArgs::UNRESUMED; const RETURNED: usize = CoroutineArgs::RETURNED; /// Coroutine has panicked and is poisoned. const POISONED: usize = CoroutineArgs::POISONED; - -/// Number of variants to reserve in coroutine state. Corresponds to -/// `UNRESUMED` (beginning of a coroutine) and `RETURNED`/`POISONED` -/// (end of a coroutine) states. -const RESERVED_VARIANTS: usize = 3; +/// Number of reserved variants of coroutine state. +const RESERVED_VARIANTS: usize = CoroutineArgs::RESERVED_VARIANTS; /// A `yield` point in the coroutine. struct SuspensionPoint<'tcx> {