diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_attr/src/builtin.rs | 591 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/terminator.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_expand/src/base.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 105 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 29 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/stability.rs | 8 |
6 files changed, 405 insertions, 342 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index d6dbdd3975e..a29e389953e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -226,307 +226,95 @@ impl UnstableReason { } } -/// Collects stability info from all stability attributes in `attrs`. -/// Returns `None` if no stability attributes are found. +/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules` +/// attributes in `attrs`. Returns `None` if no stability attributes are found. pub fn find_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) -{ - find_stability_generic(sess, attrs.iter(), item_sp) -} - -fn find_stability_generic<'a, I>( - sess: &Session, - attrs_iter: I, - item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) -where - I: Iterator<Item = &'a Attribute>, -{ - use StabilityLevel::*; - +) -> Option<(Stability, Span)> { let mut stab: Option<(Stability, Span)> = None; - let mut const_stab: Option<(ConstStability, Span)> = None; - let mut body_stab: Option<(DefaultBodyStability, Span)> = None; - let mut promotable = false; let mut allowed_through_unstable_modules = false; - 'outer: for attr in attrs_iter { - if ![ - sym::rustc_const_unstable, - sym::rustc_const_stable, - sym::unstable, - sym::stable, - sym::rustc_promotable, - sym::rustc_allowed_through_unstable_modules, - sym::rustc_default_body_unstable, - ] - .iter() - .any(|&s| attr.has_name(s)) - { - continue; // not a stability level - } - - let meta = attr.meta(); + for attr in attrs { + match attr.name_or_empty() { + sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true, + sym::unstable => { + if stab.is_some() { + handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels); + break; + } - if attr.has_name(sym::rustc_promotable) { - promotable = true; - } else if attr.has_name(sym::rustc_allowed_through_unstable_modules) { - allowed_through_unstable_modules = true; - } - // attributes with data - else if let Some(meta @ MetaItem { kind: MetaItemKind::List(metas), .. }) = &meta { - let get = |meta: &MetaItem, item: &mut Option<Symbol>| { - if item.is_some() { - handle_errors( - &sess.parse_sess, - meta.span, - AttrError::MultipleItem(pprust::path_to_string(&meta.path)), - ); - return false; + if let Some((feature, level)) = parse_unstability(sess, attr) { + stab = Some((Stability { level, feature }, attr.span)); } - if let Some(v) = meta.value_str() { - *item = Some(v); - true - } else { - sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); - false + } + sym::stable => { + if stab.is_some() { + handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels); + break; } - }; + if let Some((feature, level)) = parse_stability(sess, attr) { + stab = Some((Stability { level, feature }, attr.span)); + } + } + _ => {} + } + } - let meta_name = meta.name_or_empty(); - match meta_name { - sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => { - if meta_name == sym::unstable && stab.is_some() { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::MultipleStabilityLevels, - ); - break; - } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::MultipleStabilityLevels, - ); - break; - } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::MultipleStabilityLevels, - ); - break; - } + if allowed_through_unstable_modules { + match &mut stab { + Some(( + Stability { + level: StabilityLevel::Stable { allowed_through_unstable_modules, .. }, + .. + }, + _, + )) => *allowed_through_unstable_modules = true, + _ => { + sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); + } + } + } - let mut feature = None; - let mut reason = None; - let mut issue = None; - let mut issue_num = None; - let mut is_soft = false; - let mut implied_by = None; - for meta in metas { - let Some(mi) = meta.meta_item() else { - handle_errors( - &sess.parse_sess, - meta.span(), - AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), - ); - continue 'outer; - }; - match mi.name_or_empty() { - sym::feature => { - if !get(mi, &mut feature) { - continue 'outer; - } - } - sym::reason => { - if !get(mi, &mut reason) { - continue 'outer; - } - } - sym::issue => { - if !get(mi, &mut issue) { - continue 'outer; - } + stab +} - // These unwraps are safe because `get` ensures the meta item - // is a name/value pair string literal. - issue_num = match issue.unwrap().as_str() { - "none" => None, - issue => match issue.parse::<NonZeroU32>() { - Ok(num) => Some(num), - Err(err) => { - sess.emit_err( - session_diagnostics::InvalidIssueString { - span: mi.span, - cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( - mi.name_value_literal_span().unwrap(), - err.kind(), - ), - }, - ); - continue 'outer; - } - }, - }; - } - sym::soft => { - if !mi.is_word() { - sess.emit_err(session_diagnostics::SoftNoArgs { - span: mi.span, - }); - } - is_soft = true; - } - sym::implied_by => { - if !get(mi, &mut implied_by) { - continue 'outer; - } - } - _ => { - handle_errors( - &sess.parse_sess, - meta.span(), - AttrError::UnknownMetaItem( - pprust::path_to_string(&mi.path), - &["feature", "reason", "issue", "soft"], - ), - ); - continue 'outer; - } - } - } +/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` +/// attributes in `attrs`. Returns `None` if no stability attributes are found. +pub fn find_const_stability( + sess: &Session, + attrs: &[Attribute], + item_sp: Span, +) -> Option<(ConstStability, Span)> { + let mut const_stab: Option<(ConstStability, Span)> = None; + let mut promotable = false; - match (feature, reason, issue) { - (Some(feature), reason, Some(_)) => { - if !rustc_lexer::is_ident(feature.as_str()) { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::NonIdentFeature, - ); - continue; - } - let level = Unstable { - reason: UnstableReason::from_opt_reason(reason), - issue: issue_num, - is_soft, - implied_by, - }; - if sym::unstable == meta_name { - stab = Some((Stability { level, feature }, attr.span)); - } else if sym::rustc_const_unstable == meta_name { - const_stab = Some(( - ConstStability { level, feature, promotable: false }, - attr.span, - )); - } else if sym::rustc_default_body_unstable == meta_name { - body_stab = - Some((DefaultBodyStability { level, feature }, attr.span)); - } else { - unreachable!("Unknown stability attribute {meta_name}"); - } - } - (None, _, _) => { - handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); - continue; - } - _ => { - sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }); - continue; - } - } + for attr in attrs { + match attr.name_or_empty() { + sym::rustc_promotable => promotable = true, + sym::rustc_const_unstable => { + if const_stab.is_some() { + handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels); + break; } - sym::rustc_const_stable | sym::stable => { - if meta_name == sym::stable && stab.is_some() { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::MultipleStabilityLevels, - ); - break; - } else if meta_name == sym::rustc_const_stable && const_stab.is_some() { - handle_errors( - &sess.parse_sess, - attr.span, - AttrError::MultipleStabilityLevels, - ); - break; - } - - let mut feature = None; - let mut since = None; - for meta in metas { - match meta { - NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() { - sym::feature => { - if !get(mi, &mut feature) { - continue 'outer; - } - } - sym::since => { - if !get(mi, &mut since) { - continue 'outer; - } - } - _ => { - handle_errors( - &sess.parse_sess, - meta.span(), - AttrError::UnknownMetaItem( - pprust::path_to_string(&mi.path), - &["feature", "since"], - ), - ); - continue 'outer; - } - }, - NestedMetaItem::Lit(lit) => { - handle_errors( - &sess.parse_sess, - lit.span, - AttrError::UnsupportedLiteral( - UnsupportedLiteralReason::Generic, - false, - ), - ); - continue 'outer; - } - } - } - - if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { - since = Some(rust_version_symbol()); - } - match (feature, since) { - (Some(feature), Some(since)) => { - let level = Stable { since, allowed_through_unstable_modules: false }; - if sym::stable == meta_name { - stab = Some((Stability { level, feature }, attr.span)); - } else { - const_stab = Some(( - ConstStability { level, feature, promotable: false }, - attr.span, - )); - } - } - (None, _) => { - handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); - continue; - } - _ => { - handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince); - continue; - } - } + if let Some((feature, level)) = parse_unstability(sess, attr) { + const_stab = + Some((ConstStability { level, feature, promotable: false }, attr.span)); + } + } + sym::rustc_const_stable => { + if const_stab.is_some() { + handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels); + break; + } + if let Some((feature, level)) = parse_stability(sess, attr) { + const_stab = + Some((ConstStability { level, feature, promotable: false }, attr.span)); } - _ => unreachable!(), } + _ => {} } } @@ -538,22 +326,237 @@ where } } - if allowed_through_unstable_modules { - match &mut stab { - Some(( - Stability { - level: StabilityLevel::Stable { allowed_through_unstable_modules, .. }, - .. - }, - _, - )) => *allowed_through_unstable_modules = true, + const_stab +} + +/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. +/// Returns `None` if no stability attributes are found. +pub fn find_body_stability( + sess: &Session, + attrs: &[Attribute], +) -> Option<(DefaultBodyStability, Span)> { + let mut body_stab: Option<(DefaultBodyStability, Span)> = None; + + for attr in attrs { + if attr.has_name(sym::rustc_default_body_unstable) { + if body_stab.is_some() { + handle_errors(&sess.parse_sess, attr.span, AttrError::MultipleStabilityLevels); + break; + } + + if let Some((feature, level)) = parse_unstability(sess, attr) { + body_stab = Some((DefaultBodyStability { level, feature }, attr.span)); + } + } + } + + body_stab +} + +/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and +/// its stability information. +fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { + let meta = attr.meta()?; + let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None }; + let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| { + if item.is_some() { + handle_errors( + &sess.parse_sess, + meta.span, + AttrError::MultipleItem(pprust::path_to_string(&meta.path)), + ); + return false; + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); + false + } + }; + + let mut feature = None; + let mut since = None; + for meta in metas { + let Some(mi) = meta.meta_item() else { + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), + ); + return None; + }; + + match mi.name_or_empty() { + sym::feature => { + if !insert_or_error(mi, &mut feature) { + return None; + } + } + sym::since => { + if !insert_or_error(mi, &mut since) { + return None; + } + } _ => { - sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnknownMetaItem( + pprust::path_to_string(&mi.path), + &["feature", "since"], + ), + ); + return None; } } } - (stab, const_stab, body_stab) + if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { + since = Some(rust_version_symbol()); + } + + match (feature, since) { + (Some(feature), Some(since)) => { + let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; + Some((feature, level)) + } + (None, _) => { + handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); + None + } + _ => { + handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince); + None + } + } +} + +/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` +/// attribute, and return the feature name and its stability information. +fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { + let meta = attr.meta()?; + let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None }; + let insert_or_error = |meta: &MetaItem, item: &mut Option<Symbol>| { + if item.is_some() { + handle_errors( + &sess.parse_sess, + meta.span, + AttrError::MultipleItem(pprust::path_to_string(&meta.path)), + ); + return false; + } + if let Some(v) = meta.value_str() { + *item = Some(v); + true + } else { + sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); + false + } + }; + + let mut feature = None; + let mut reason = None; + let mut issue = None; + let mut issue_num = None; + let mut is_soft = false; + let mut implied_by = None; + for meta in metas { + let Some(mi) = meta.meta_item() else { + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false), + ); + return None; + }; + + match mi.name_or_empty() { + sym::feature => { + if !insert_or_error(mi, &mut feature) { + return None; + } + } + sym::reason => { + if !insert_or_error(mi, &mut reason) { + return None; + } + } + sym::issue => { + if !insert_or_error(mi, &mut issue) { + return None; + } + + // These unwraps are safe because `insert_or_error` ensures the meta item + // is a name/value pair string literal. + issue_num = match issue.unwrap().as_str() { + "none" => None, + issue => match issue.parse::<NonZeroU32>() { + Ok(num) => Some(num), + Err(err) => { + sess.emit_err( + session_diagnostics::InvalidIssueString { + span: mi.span, + cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( + mi.name_value_literal_span().unwrap(), + err.kind(), + ), + }, + ); + return None; + } + }, + }; + } + sym::soft => { + if !mi.is_word() { + sess.emit_err(session_diagnostics::SoftNoArgs { span: mi.span }); + } + is_soft = true; + } + sym::implied_by => { + if !insert_or_error(mi, &mut implied_by) { + return None; + } + } + _ => { + handle_errors( + &sess.parse_sess, + meta.span(), + AttrError::UnknownMetaItem( + pprust::path_to_string(&mi.path), + &["feature", "reason", "issue", "soft", "implied_by"], + ), + ); + return None; + } + } + } + + match (feature, reason, issue) { + (Some(feature), reason, Some(_)) => { + if !rustc_lexer::is_ident(feature.as_str()) { + handle_errors(&sess.parse_sess, attr.span, AttrError::NonIdentFeature); + return None; + } + let level = StabilityLevel::Unstable { + reason: UnstableReason::from_opt_reason(reason), + issue: issue_num, + is_soft, + implied_by, + }; + Some((feature, level)) + } + (None, _, _) => { + handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); + return None; + } + _ => { + sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }); + return None; + } + } } pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> { diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index c2d1bc11c37..fc83985eaca 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -539,7 +539,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let mut receiver = args[0].clone(); let receiver_place = loop { match receiver.layout.ty.kind() { - ty::Ref(..) | ty::RawPtr(..) => break self.deref_operand(&receiver)?, + ty::Ref(..) | ty::RawPtr(..) => { + // We do *not* use `deref_operand` here: we don't want to conceptually + // create a place that must be dereferenceable, since the receiver might + // be a raw pointer and (for `*const dyn Trait`) we don't need to + // actually access memory to resolve this method. + // Also see <https://github.com/rust-lang/miri/issues/2786>. + let val = self.read_immediate(&receiver)?; + break self.ref_to_mplace(&val)?; + } ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values ty::Dynamic(.., ty::DynStar) => { // Not clear how to handle this, so far we assume the receiver is always a pointer. diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index d32af10914e..caa2a201c75 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -793,7 +793,9 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span); + let stability = attr::find_stability(&sess, attrs, span); + let const_stability = attr::find_const_stability(&sess, attrs, span); + let body_stability = attr::find_body_stability(&sess, attrs); if let Some((_, sp)) = const_stability { sess.emit_err(errors::MacroConstStability { span: sp, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 737532b98a4..491bd04f346 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1544,42 +1544,81 @@ fn check_return_position_impl_trait_in_trait_bounds<'tcx>( span: Span, ) { let tcx = wfcx.tcx(); - if let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) - && assoc_item.container == ty::AssocItemContainer::TraitContainer - { - // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering - // strategy, we can't just call `check_associated_item` on the new RPITITs, - // because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. - // That's because we need to check that the bounds of the RPITIT hold using - // the special substs that we create during opaque type lowering, otherwise we're - // getting a bunch of early bound and free regions mixed up... Haven't looked too - // deep into this, though. - for arg in fn_output.walk() { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - // RPITITs are always eagerly normalized into opaques, so always look for an - // opaque here. - && let ty::Alias(ty::Opaque, opaque_ty) = ty.kind() - && let Some(opaque_def_id) = opaque_ty.def_id.as_local() - && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() - && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin - && source == fn_def_id + let Some(assoc_item) = tcx.opt_associated_item(fn_def_id.to_def_id()) else { + return; + }; + if assoc_item.container != ty::AssocItemContainer::TraitContainer { + return; + } + fn_output.visit_with(&mut ImplTraitInTraitFinder { + wfcx, + fn_def_id, + depth: ty::INNERMOST, + seen: FxHashSet::default(), + }); +} + +// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): Even with the new lowering +// strategy, we can't just call `check_associated_item` on the new RPITITs, +// because tests like `tests/ui/async-await/in-trait/implied-bounds.rs` will fail. +// That's because we need to check that the bounds of the RPITIT hold using +// the special substs that we create during opaque type lowering, otherwise we're +// getting a bunch of early bound and free regions mixed up... Haven't looked too +// deep into this, though. +struct ImplTraitInTraitFinder<'a, 'tcx> { + wfcx: &'a WfCheckingCtxt<'a, 'tcx>, + fn_def_id: LocalDefId, + depth: ty::DebruijnIndex, + seen: FxHashSet<DefId>, +} +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { + type BreakTy = !; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<!> { + let tcx = self.wfcx.tcx(); + if let ty::Alias(ty::Opaque, unshifted_opaque_ty) = *ty.kind() + && self.seen.insert(unshifted_opaque_ty.def_id) + && let Some(opaque_def_id) = unshifted_opaque_ty.def_id.as_local() + && let opaque = tcx.hir().expect_item(opaque_def_id).expect_opaque_ty() + && let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin + && source == self.fn_def_id + { + let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| { + if let ty::ReLateBound(index, bv) = re.kind() { + if depth != ty::INNERMOST { + return tcx.mk_re_error_with_message( + DUMMY_SP, + "we shouldn't walk non-predicate binders with `impl Trait`...", + ); + } + tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv) + } else { + re + } + }); + for (bound, bound_span) in tcx + .bound_explicit_item_bounds(opaque_ty.def_id) + .subst_iter_copied(tcx, opaque_ty.substs) { - let span = tcx.def_span(opaque_ty.def_id); - let bounds = wfcx.tcx().explicit_item_bounds(opaque_ty.def_id); - let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| { - let bound = ty::EarlyBinder(bound).subst(tcx, opaque_ty.substs); - let normalized_bound = wfcx.normalize(span, None, bound); - traits::wf::predicate_obligations( - wfcx.infcx, - wfcx.param_env, - wfcx.body_def_id, - normalized_bound, - bound_span, - ) - }); - wfcx.register_obligations(wf_obligations); + let bound = self.wfcx.normalize(bound_span, None, bound); + self.wfcx.register_obligations(traits::wf::predicate_obligations( + self.wfcx.infcx, + self.wfcx.param_env, + self.wfcx.body_def_id, + bound, + bound_span, + )); + // Set the debruijn index back to innermost here, since we already eagerly + // shifted the substs that we use to generate these bounds. This is unfortunately + // subtly different behavior than the `ImplTraitInTraitFinder` we use in `param_env`, + // but that function doesn't actually need to normalize the bound it's visiting + // (whereas we have to do so here)... + let old_depth = std::mem::replace(&mut self.depth, ty::INNERMOST); + bound.visit_with(self); + self.depth = old_depth; } } + ty.super_visit_with(self) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 18a49ef2f01..5fda4e191c2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -983,13 +983,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .must_apply_modulo_regions() { - diag.span_suggestion_verbose( - expr.span.shrink_to_hi(), - "consider using clone here", - ".clone()", - Applicability::MachineApplicable, - ); - return true; + let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {}.clone()", ident), + None => ".clone()".to_string() + }; + + diag.span_suggestion_verbose( + expr.span.shrink_to_hi(), + "consider using clone here", + suggestion, + Applicability::MachineApplicable, + ); + return true; } false } @@ -1150,13 +1155,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - diag.span_suggestion( + let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {}.is_some()", ident), + None => ".is_some()".to_string(), + }; + + diag.span_suggestion_verbose( expr.span.shrink_to_hi(), "use `Option::is_some` to test if the `Option` has a value", - ".is_some()", + suggestion, Applicability::MachineApplicable, ); - true } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6d0cfea00d1..4a1ba19c920 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -159,7 +159,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } - let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); + let stab = attr::find_stability(&self.tcx.sess, attrs, item_sp); + let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item_sp); + let body_stab = attr::find_body_stability(&self.tcx.sess, attrs); let mut const_span = None; let const_stab = const_stab.map(|(const_stab, const_span_node)| { @@ -742,8 +744,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api { let attrs = self.tcx.hir().attrs(item.hir_id()); - let (stab, const_stab, _) = - attr::find_stability(&self.tcx.sess, attrs, item.span); + let stab = attr::find_stability(&self.tcx.sess, attrs, item.span); + let const_stab = attr::find_const_stability(&self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because |
