diff options
| author | bors <bors@rust-lang.org> | 2022-06-06 08:02:38 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-06-06 08:02:38 +0000 |
| commit | e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd (patch) | |
| tree | 5408b1ac29becada73eddc0d75196e5b1e66d289 /compiler | |
| parent | 6609c6734de4df43e24d7672f8ae8786ecc8047e (diff) | |
| parent | 1258fa9d9be2811497c03235cd3db60aad6a9763 (diff) | |
| download | rust-e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd.tar.gz rust-e70c60d34b9783a2fd3171d88d248c2e0ec8ecdd.zip | |
Auto merge of #97783 - matthiaskrgr:rollup-14t9htt, r=matthiaskrgr
Rollup of 7 pull requests
Successful merges:
- #90905 (Add empty impl blocks if they have documentation)
- #97683 (Fail gracefully when encountering an HRTB in APIT. )
- #97721 (Do `suggest_await_before_try` with infer variables in self, and clean up binders)
- #97752 (typo: `-Zcodegen-backend=llvm -Cpasses=list` should work now)
- #97759 (Suggest adding `{}` for `'label: non_block_expr`)
- #97764 (use strict provenance APIs)
- #97765 (Restore a test that was intended to test `as` cast to ptr)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_driver/src/lib.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 64 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/lifetimes.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs | 48 |
5 files changed, 146 insertions, 47 deletions
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 179a184536e..1a7972716d3 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1055,13 +1055,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { } if cg_flags.iter().any(|x| *x == "passes=list") { - let backend_name = debug_flags.iter().find_map(|x| { - if x.starts_with("codegen-backend=") { - Some(&x["codegen-backends=".len()..]) - } else { - None - } - }); + let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); get_codegen_backend(&None, backend_name).print_passes(); return None; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index cb2e66090e7..83821b5b536 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -734,7 +734,7 @@ impl<'hir> WherePredicate<'hir> { } } -#[derive(Debug, HashStable_Generic, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)] pub enum PredicateOrigin { WhereClause, GenericParam, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 63c7decbb2f..b786c52e688 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -13,10 +13,13 @@ use rustc_ast::tokenstream::Spacing; use rustc_ast::util::classify; use rustc_ast::util::literal::LitError; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; +use rustc_ast::visit::Visitor; +use rustc_ast::StmtKind; use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID}; use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast_pretty::pprust; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, PResult}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; @@ -1548,9 +1551,66 @@ impl<'a> Parser<'a> { Ok(self.mk_expr_err(lo)) } else { let msg = "expected `while`, `for`, `loop` or `{` after a label"; - self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); + + let mut err = self.struct_span_err(self.token.span, msg); + err.span_label(self.token.span, msg); + // Continue as an expression in an effort to recover on `'label: non_block_expr`. - self.parse_expr() + let expr = self.parse_expr().map(|expr| { + let span = expr.span; + + let found_labeled_breaks = { + struct FindLabeledBreaksVisitor(bool); + + impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor { + fn visit_expr_post(&mut self, ex: &'ast Expr) { + if let ExprKind::Break(Some(_label), _) = ex.kind { + self.0 = true; + } + } + } + + let mut vis = FindLabeledBreaksVisitor(false); + vis.visit_expr(&expr); + vis.0 + }; + + // Suggestion involves adding a (as of time of writing this, unstable) labeled block. + // + // If there are no breaks that may use this label, suggest removing the label and + // recover to the unmodified expression. + if !found_labeled_breaks { + let msg = "consider removing the label"; + err.span_suggestion_verbose( + lo.until(span), + msg, + "", + Applicability::MachineApplicable, + ); + + return expr; + } + + let sugg_msg = "consider enclosing expression in a block"; + let suggestions = vec![ + (span.shrink_to_lo(), "{ ".to_owned()), + (span.shrink_to_hi(), " }".to_owned()), + ]; + + err.multipart_suggestion_verbose( + sugg_msg, + suggestions, + Applicability::MachineApplicable, + ); + + // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`. + let stmt = self.mk_stmt(span, StmtKind::Expr(expr)); + let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span); + self.mk_expr(span, ExprKind::Block(blk, label), ThinVec::new()) + }); + + err.emit(); + expr }?; if !ate_colon && consume_colon { diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 11f80b314d7..bfc42902be4 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -207,6 +207,13 @@ enum Scope<'a> { /// In some cases not allowing late bounds allows us to avoid ICEs. /// This is almost ways set to true. allow_late_bound: bool, + + /// If this binder comes from a where clause, specify how it was created. + /// This is used to diagnose inaccessible lifetimes in APIT: + /// ```ignore (illustrative) + /// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} + /// ``` + where_bound_origin: Option<hir::PredicateOrigin>, }, /// Lifetimes introduced by a fn are scoped to the call-site for that fn, @@ -277,8 +284,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { opaque_type_parent, scope_type, hir_id, - s: _, allow_late_bound, + where_bound_origin, + s: _, } => f .debug_struct("Binder") .field("lifetimes", lifetimes) @@ -286,8 +294,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("opaque_type_parent", opaque_type_parent) .field("scope_type", scope_type) .field("hir_id", hir_id) - .field("s", &"..") .field("allow_late_bound", allow_late_bound) + .field("where_bound_origin", where_bound_origin) + .field("s", &"..") .finish(), Scope::Body { id, s: _ } => { f.debug_struct("Body").field("id", id).field("s", &"..").finish() @@ -638,6 +647,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id)); } @@ -753,6 +763,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { scope_type: BinderScopeType::Normal, s: ROOT_SCOPE, allow_late_bound: false, + where_bound_origin: None, }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -818,6 +829,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, |this| { // a bare fn has no bounds, so everything @@ -1006,6 +1018,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: false, + where_bound_origin: None, }; this.with(scope, |this| { this.visit_generics(generics); @@ -1026,6 +1039,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: false, + where_bound_origin: None, }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -1084,6 +1098,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: false, + where_bound_origin: None, }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -1151,6 +1166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, |this| { let scope = Scope::TraitRefBoundary { s: this.scope }; @@ -1266,6 +1282,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref bounded_ty, bounds, ref bound_generic_params, + origin, .. }) => { let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = @@ -1296,6 +1313,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type: BinderScopeType::Normal, allow_late_bound: true, + where_bound_origin: Some(origin), }; this.with(scope, |this| { this.visit_ty(&bounded_ty); @@ -1368,6 +1386,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, |this| { intravisit::walk_param_bound(this, bound); @@ -1420,6 +1439,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { opaque_type_parent: false, scope_type, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, |this| { walk_list!(this, visit_generic_param, trait_ref.bound_generic_params); @@ -1680,6 +1700,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { opaque_type_parent: true, scope_type: BinderScopeType::Normal, allow_late_bound: true, + where_bound_origin: None, }; self.with(scope, walk); } @@ -1783,12 +1804,48 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } self.insert_lifetime(lifetime_ref, def); - } else { - self.tcx.sess.delay_span_bug( - lifetime_ref.span, - &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), - ); + return; } + + // We may fail to resolve higher-ranked lifetimes that are mentionned by APIT. + // AST-based resolution does not care for impl-trait desugaring, which are the + // responibility of lowering. This may create a mismatch between the resolution + // AST found (`region_def_id`) which points to HRTB, and what HIR allows. + // ``` + // fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {} + // ``` + // + // In such case, walk back the binders to diagnose it properly. + let mut scope = self.scope; + loop { + match *scope { + Scope::Binder { + where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), .. + } => { + let mut err = self.tcx.sess.struct_span_err( + lifetime_ref.span, + "`impl Trait` can only mention lifetimes bound at the fn or impl level", + ); + err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here"); + err.emit(); + return; + } + Scope::Root => break, + Scope::Binder { s, .. } + | Scope::Body { s, .. } + | Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } => { + scope = s; + } + } + } + + self.tcx.sess.delay_span_bug( + lifetime_ref.span, + &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,), + ); } fn visit_segment_args( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fd0732f51d5..185f500808f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -5,7 +5,7 @@ use super::{ use crate::autoderef::Autoderef; use crate::infer::InferCtxt; -use crate::traits::normalize_projection_type; +use crate::traits::normalize_to; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -2706,55 +2706,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - - // Do not check on infer_types to avoid panic in evaluate_obligation. - if self_ty.has_infer_types() { - return; - } - let self_ty = self.tcx.erase_regions(self_ty); - let impls_future = self.type_implements_trait( future_trait, - self_ty.skip_binder(), + self.tcx.erase_late_bound_regions(self_ty), ty::List::empty(), obligation.param_env, ); + if !impls_future.must_apply_modulo_regions() { + return; + } let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; // `<T as Future>::Output` - let projection_ty = ty::ProjectionTy { - // `T` - substs: self.tcx.mk_substs_trait( - trait_pred.self_ty().skip_binder(), - &self.fresh_substs_for_item(span, item_def_id)[1..], - ), - // `Future::Output` - item_def_id, - }; - - let mut selcx = SelectionContext::new(self); - - let mut obligations = vec![]; - let normalized_ty = normalize_projection_type( - &mut selcx, + let projection_ty = trait_pred.map_bound(|trait_pred| { + self.tcx.mk_projection( + item_def_id, + // Future::Output has no substs + self.tcx.mk_substs_trait(trait_pred.self_ty(), &[]), + ) + }); + let projection_ty = normalize_to( + &mut SelectionContext::new(self), obligation.param_env, - projection_ty, obligation.cause.clone(), - 0, - &mut obligations, + projection_ty, + &mut vec![], ); debug!( "suggest_await_before_try: normalized_projection_type {:?}", - self.resolve_vars_if_possible(normalized_ty) + self.resolve_vars_if_possible(projection_ty) ); let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, - trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())), + trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), ); debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); if self.predicate_may_hold(&try_obligation) - && impls_future.must_apply_modulo_regions() && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) && snippet.ends_with('?') { |
