diff options
| author | bors <bors@rust-lang.org> | 2022-12-24 09:41:11 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-12-24 09:41:11 +0000 |
| commit | d23554fae855d884761d549cd6ee6537450b0f3c (patch) | |
| tree | b44bd3e79fa5019f0e8648737e71c432bc784188 /compiler/rustc_hir_analysis/src/check | |
| parent | 245357f61939d2b6d15f8c6b15f7026396f95871 (diff) | |
| parent | e52e0d855799fe651922be4a038fe84fe9009c72 (diff) | |
| download | rust-d23554fae855d884761d549cd6ee6537450b0f3c.tar.gz rust-d23554fae855d884761d549cd6ee6537450b0f3c.zip | |
Auto merge of #2738 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/compare_method.rs | 116 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/intrinsic.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 |
5 files changed, 120 insertions, 33 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index aa01feb3a1e..a714663741b 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -99,18 +99,17 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - span: Span, ) -> bool { // We don't just accept all !needs_drop fields, due to semver concerns. match ty.kind() { ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) ty::Tuple(tys) => { // allow tuples of allowed types - tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span)) + tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env)) } ty::Array(elem, _len) => { // Like `Copy`, we do *not* special-case length 0. - allowed_union_field(*elem, tcx, param_env, span) + allowed_union_field(*elem, tcx, param_env) } _ => { // Fallback case: allow `ManuallyDrop` and things that are `Copy`. @@ -124,7 +123,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b for field in &def.non_enum_variant().fields { let field_ty = field.ty(tcx, substs); - if !allowed_union_field(field_ty, tcx, param_env, span) { + if !allowed_union_field(field_ty, tcx, param_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { // We are currently checking the type this field came from, so it must be local. Some(Node::Field(field)) => (field.span, field.ty.span), @@ -163,7 +162,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b } /// Check that a `static` is inhabited. -fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { +fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Make sure statics are inhabited. // Other parts of the compiler assume that there are no uninhabited places. In principle it // would be enough to check this for `extern` statics, as statics with an initializer will @@ -213,7 +212,7 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". -fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { +fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) { let item = tcx.hir().item(id); let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item"); @@ -246,8 +245,8 @@ fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result /// in "inheriting lifetimes". #[instrument(level = "debug", skip(tcx, span))] -pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( - tcx: TyCtxt<'tcx>, +pub(super) fn check_opaque_for_inheriting_lifetimes( + tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span, ) { @@ -497,7 +496,7 @@ fn is_enum_of_nonnullable_ptr<'tcx>( matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..)) } -fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { +fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() { if match tcx.type_of(def_id).kind() { ty::RawPtr(_) => false, @@ -509,7 +508,7 @@ fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { } } -fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { +fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { debug!( "check_item_type(it.def_id={:?}, it.name={})", id.owner_id, @@ -1161,7 +1160,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } #[allow(trivial_numeric_casts)] -fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { +fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); def.destructor(tcx); // force the destructor to be evaluated diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 6b9ce9a4599..c6bda9b4641 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -71,8 +71,14 @@ pub(crate) fn compare_impl_method<'tcx>( return; } - if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) - { + if let Err(_) = compare_predicate_entailment( + tcx, + impl_m, + impl_m_span, + trait_m, + impl_trait_ref, + CheckImpliedWfMode::Check, + ) { return; } } @@ -150,6 +156,7 @@ fn compare_predicate_entailment<'tcx>( impl_m_span: Span, trait_m: &ty::AssocItem, impl_trait_ref: ty::TraitRef<'tcx>, + check_implied_wf: CheckImpliedWfMode, ) -> Result<(), ErrorGuaranteed> { let trait_to_impl_substs = impl_trait_ref.substs; @@ -255,15 +262,15 @@ fn compare_predicate_entailment<'tcx>( let mut wf_tys = FxIndexSet::default(); - let impl_sig = infcx.replace_bound_vars_with_fresh_vars( + let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, tcx.fn_sig(impl_m.def_id), ); + let unnormalized_impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(unnormalized_impl_sig)); let norm_cause = ObligationCause::misc(impl_m_span, impl_m_hir_id); - let impl_sig = ocx.normalize(&norm_cause, param_env, impl_sig); - let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)); + let impl_fty = ocx.normalize(&norm_cause, param_env, unnormalized_impl_fty); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); @@ -304,29 +311,108 @@ fn compare_predicate_entailment<'tcx>( return Err(emitted); } + if check_implied_wf == CheckImpliedWfMode::Check { + // We need to check that the impl's args are well-formed given + // the hybrid param-env (impl + trait method where-clauses). + ocx.register_obligation(traits::Obligation::new( + infcx.tcx, + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())), + )); + } + let emit_implied_wf_lint = || { + infcx.tcx.struct_span_lint_hir( + rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT, + impl_m_hir_id, + infcx.tcx.def_span(impl_m.def_id), + "impl method assumes more implied bounds than the corresponding trait method", + |lint| lint, + ); + }; + // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.select_all_or_error(); if !errors.is_empty() { - let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); - return Err(reported); + match check_implied_wf { + CheckImpliedWfMode::Check => { + return compare_predicate_entailment( + tcx, + impl_m, + impl_m_span, + trait_m, + impl_trait_ref, + CheckImpliedWfMode::Skip, + ) + .map(|()| { + // If the skip-mode was successful, emit a lint. + emit_implied_wf_lint(); + }); + } + CheckImpliedWfMode::Skip => { + let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); + return Err(reported); + } + } } // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let outlives_environment = OutlivesEnvironment::with_bounds( + let outlives_env = OutlivesEnvironment::with_bounds( param_env, Some(infcx), - infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()), ); - infcx.check_region_obligations_and_report_errors( - impl_m.def_id.expect_local(), - &outlives_environment, + infcx.process_registered_region_obligations( + outlives_env.region_bound_pairs(), + outlives_env.param_env, ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT + // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` + match check_implied_wf { + CheckImpliedWfMode::Check => { + return compare_predicate_entailment( + tcx, + impl_m, + impl_m_span, + trait_m, + impl_trait_ref, + CheckImpliedWfMode::Skip, + ) + .map(|()| { + // If the skip-mode was successful, emit a lint. + emit_implied_wf_lint(); + }); + } + CheckImpliedWfMode::Skip => { + if infcx.tainted_by_errors().is_none() { + infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors); + } + return Err(tcx + .sess + .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted")); + } + } + } Ok(()) } +#[derive(Debug, PartialEq, Eq)] +enum CheckImpliedWfMode { + /// Checks implied well-formedness of the impl method. If it fails, we will + /// re-check with `Skip`, and emit a lint if it succeeds. + Check, + /// Skips checking implied well-formedness of the impl method, but will emit + /// a lint if the `compare_predicate_entailment` succeeded. This means that + /// the reason that we had failed earlier during `Check` was due to the impl + /// having stronger requirements than the trait. + Skip, +} + fn compare_asyncness<'tcx>( tcx: TyCtxt<'tcx>, impl_m: &ty::AssocItem, @@ -405,6 +491,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( tcx.fn_sig(impl_m.def_id), ), ); + impl_sig.error_reported()?; let impl_return_ty = impl_sig.output(); // Normalize the trait signature with liberated bound vars, passing it through @@ -419,6 +506,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( ) .fold_with(&mut collector); let trait_sig = ocx.normalize(&norm_cause, param_env, unnormalized_trait_sig); + trait_sig.error_reported()?; let trait_return_ty = trait_sig.output(); let wf_tys = FxIndexSet::from_iter( @@ -1429,8 +1517,8 @@ fn compare_generic_param_kinds<'tcx>( } /// Use `tcx.compare_assoc_const_impl_item_with_trait_item` instead -pub(crate) fn raw_compare_const_impl<'tcx>( - tcx: TyCtxt<'tcx>, +pub(crate) fn raw_compare_const_impl( + tcx: TyCtxt<'_>, (impl_const_item_def, trait_const_item_def): (LocalDefId, DefId), ) -> Result<(), ErrorGuaranteed> { let impl_const_item = tcx.associated_item(impl_const_item_def); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 69e54b41d4c..598dc2dca5c 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -75,7 +75,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir sym::abort | sym::assert_inhabited | sym::assert_zero_valid - | sym::assert_uninit_valid + | sym::assert_mem_uninitialized_valid | sym::size_of | sym::min_align_of | sym::needs_drop @@ -193,9 +193,9 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { } sym::rustc_peek => (1, vec![param(0)], param(0)), sym::caller_location => (0, vec![], tcx.caller_location_ty()), - sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => { - (1, Vec::new(), tcx.mk_unit()) - } + sym::assert_inhabited + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()), sym::forget => (1, vec![param(0)], tcx.mk_unit()), sym::transmute => (2, vec![param(0)], param(1)), sym::prefetch_read_data diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 57f0cae12bb..ed2aed293a7 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -115,10 +115,10 @@ fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { /// Given a `DefId` for an opaque type in return position, find its parent item's return /// expressions. -fn get_owner_return_paths<'tcx>( - tcx: TyCtxt<'tcx>, +fn get_owner_return_paths( + tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> { +) -> Option<(LocalDefId, ReturnsVisitor<'_>)> { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let parent_id = tcx.hir().get_parent_item(hir_id).def_id; tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 94d333c336e..aedc736b023 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1673,7 +1673,7 @@ fn check_method_receiver<'tcx>( } } -fn e0307<'tcx>(tcx: TyCtxt<'tcx>, span: Span, receiver_ty: Ty<'_>) { +fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { struct_span_err!( tcx.sess.diagnostic(), span, |
