Skip to content

Commit 6f79911

Browse files
committed
Auto merge of rust-lang#118553 - jackh726:lint-implied-bounds, r=<try>
lint incorrect implied bounds in wfcheck except for Bevy dependents Rebase of rust-lang#109763 Additionally, special cases Bevy `ParamSet` types to not trigger the lint. Opening for crater r? `@ghost`
2 parents c9d85d6 + f503f02 commit 6f79911

File tree

20 files changed

+546
-124
lines changed

20 files changed

+546
-124
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ fn check_opaque_meets_bounds<'tcx>(
356356
// Can have different predicates to their defining use
357357
hir::OpaqueTyOrigin::TyAlias { .. } => {
358358
let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
359-
let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
359+
let implied_bounds = infcx.implied_bounds_tys_compat(param_env, def_id, &wf_tys);
360360
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
361361
ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
362362
}

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ fn compare_method_predicate_entailment<'tcx>(
404404
// lifetime parameters.
405405
let outlives_env = OutlivesEnvironment::with_bounds(
406406
param_env,
407-
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
407+
infcx.implied_bounds_tys_compat(param_env, impl_m_def_id, &wf_tys),
408408
);
409409
let errors = infcx.resolve_regions(&outlives_env);
410410
if !errors.is_empty() {
@@ -880,7 +880,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
880880
// lifetime parameters.
881881
let outlives_env = OutlivesEnvironment::with_bounds(
882882
param_env,
883-
infcx.implied_bounds_tys(param_env, impl_m_def_id, wf_tys),
883+
infcx.implied_bounds_tys_compat(param_env, impl_m_def_id, &wf_tys),
884884
);
885885
ocx.resolve_regions_and_report_errors(impl_m_def_id, &outlives_env)?;
886886

@@ -2242,7 +2242,8 @@ pub(super) fn check_type_bounds<'tcx>(
22422242

22432243
// Finally, resolve all regions. This catches wily misuses of
22442244
// lifetime parameters.
2245-
let implied_bounds = infcx.implied_bounds_tys(param_env, impl_ty_def_id, assumed_wf_types);
2245+
let implied_bounds =
2246+
infcx.implied_bounds_tys_compat(param_env, impl_ty_def_id, &assumed_wf_types);
22462247
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
22472248
ocx.resolve_regions_and_report_errors(impl_ty_def_id, &outlives_env)
22482249
}

compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
161161
}
162162
let outlives_env = OutlivesEnvironment::with_bounds(
163163
param_env,
164-
infcx.implied_bounds_tys(param_env, impl_m.def_id.expect_local(), implied_wf_types),
164+
infcx.implied_bounds_tys_compat(param_env, impl_m.def_id.expect_local(), &implied_wf_types),
165165
);
166166
let errors = infcx.resolve_regions(&outlives_env);
167167
if !errors.is_empty() {

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+54-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_infer::infer::outlives::obligations::TypeOutlives;
1313
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
1414
use rustc_middle::mir::ConstraintCategory;
1515
use rustc_middle::query::Providers;
16+
use rustc_middle::ty::print::with_no_trimmed_paths;
1617
use rustc_middle::ty::trait_def::TraitSpecializationKind;
1718
use rustc_middle::ty::{
1819
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
@@ -110,8 +111,6 @@ where
110111

111112
let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
112113

113-
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
114-
115114
let errors = wfcx.select_all_or_error();
116115
if !errors.is_empty() {
117116
let err = infcx.err_ctxt().report_fulfillment_errors(errors);
@@ -126,9 +125,60 @@ where
126125
}
127126
}
128127

128+
let infcx_compat = infcx.fork();
129+
130+
debug!(?assumed_wf_types);
131+
let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, &assumed_wf_types);
129132
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
130133

131-
wfcx.ocx.resolve_regions_and_report_errors(body_def_id, &outlives_env)?;
134+
let errors = infcx.resolve_regions(&outlives_env);
135+
if errors.is_empty() {
136+
return Ok(());
137+
}
138+
139+
let implied_bounds =
140+
infcx_compat.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types);
141+
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
142+
let errors_compat = infcx_compat.resolve_regions(&outlives_env);
143+
if !errors_compat.is_empty() {
144+
return Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat));
145+
}
146+
147+
// We don't want to emit this for dependents of Bevy, for now.
148+
for ty in assumed_wf_types.iter() {
149+
match ty.kind() {
150+
ty::Adt(def, _) => {
151+
let adt_did = with_no_trimmed_paths!(infcx.tcx.def_path_str(def.0.did));
152+
if adt_did.contains("ParamSet") {
153+
return Ok(());
154+
}
155+
}
156+
_ => {}
157+
}
158+
}
159+
160+
let hir_id = tcx.local_def_id_to_hir_id(body_def_id);
161+
let (lint_level, _) = tcx
162+
.lint_level_at_node(rustc_session::lint::builtin::IMPLIED_BOUNDS_FROM_TRAIT_IMPL, hir_id);
163+
tcx.struct_span_lint_hir(
164+
rustc_session::lint::builtin::IMPLIED_BOUNDS_FROM_TRAIT_IMPL,
165+
hir_id,
166+
tcx.def_span(body_def_id),
167+
format!("{} is missing necessary lifetime bounds", tcx.def_descr(body_def_id.into())),
168+
|lint| {
169+
if !lint_level.is_error() {
170+
lint.note(
171+
"to get more detailed errors, use `#[deny(implied_bounds_from_trait_impl)]`",
172+
)
173+
} else {
174+
lint.note("more concrete lifetime errors are emitted below")
175+
}
176+
},
177+
);
178+
if true || lint_level.is_error() {
179+
infcx.err_ctxt().report_region_errors(body_def_id, &errors);
180+
}
181+
132182
infcx.tainted_by_errors().error_reported()
133183
}
134184

@@ -717,7 +767,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
717767
let infcx = tcx.infer_ctxt().build();
718768
let outlives_environment = OutlivesEnvironment::with_bounds(
719769
param_env,
720-
infcx.implied_bounds_tys(param_env, id, wf_tys.clone()),
770+
infcx.implied_bounds_tys_compat(param_env, id, wf_tys),
721771
);
722772
let region_bound_pairs = outlives_environment.region_bound_pairs();
723773

compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ fn get_impl_args(
202202
return Err(guar);
203203
}
204204

205-
let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
205+
let implied_bounds =
206+
infcx.implied_bounds_tys_compat(param_env, impl1_def_id, &assumed_wf_types);
206207
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
207208
let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
208209
let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {

compiler/rustc_lint_defs/src/builtin.rs

+42
Original file line numberDiff line numberDiff line change
@@ -3389,6 +3389,7 @@ declare_lint_pass! {
33893389
ILL_FORMED_ATTRIBUTE_INPUT,
33903390
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
33913391
IMPLIED_BOUNDS_ENTAILMENT,
3392+
IMPLIED_BOUNDS_FROM_TRAIT_IMPL,
33923393
INCOMPLETE_INCLUDE,
33933394
INDIRECT_STRUCTURAL_MATCH,
33943395
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
@@ -4621,3 +4622,44 @@ declare_lint! {
46214622
reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
46224623
};
46234624
}
4625+
4626+
declare_lint! {
4627+
/// The `implied_bounds_from_trait_impl` lint detects
4628+
/// a compiler bug allowed some code to assume invalid implied lifetime bounds.
4629+
///
4630+
/// ### Example
4631+
///
4632+
/// ```rust,compile_fail
4633+
/// #![deny(implied_bounds_from_trait_impl)]
4634+
///
4635+
/// trait Trait {
4636+
/// type Assoc;
4637+
/// }
4638+
///
4639+
/// impl<X: 'static> Trait for (X,) {
4640+
/// type Assoc = ();
4641+
/// }
4642+
///
4643+
/// struct Foo<T: Trait>(T)
4644+
/// where
4645+
/// T::Assoc: Clone; // any bound using `T::Assoc`
4646+
///
4647+
/// fn func(foo: Foo<(&str,)>) {
4648+
/// let _: &'static str = foo.0.0;
4649+
/// }
4650+
/// ```
4651+
///
4652+
/// {{produces}}
4653+
///
4654+
/// ### Explanation
4655+
///
4656+
/// FIXME: explanataion
4657+
///
4658+
pub IMPLIED_BOUNDS_FROM_TRAIT_IMPL,
4659+
Warn,
4660+
"item uses illegal implied bounds derived from a trait impl",
4661+
@future_incompatible = FutureIncompatibleInfo {
4662+
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
4663+
reference: "issue #109628 <https://github.com/rust-lang/rust/issues/109628>",
4664+
};
4665+
}

compiler/rustc_middle/src/query/erase.rs

+4
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ impl<T> EraseType for Result<&'_ T, traits::query::NoSolution> {
7474
type Result = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
7575
}
7676

77+
impl<T> EraseType for Result<&'_ [T], traits::query::NoSolution> {
78+
type Result = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
79+
}
80+
7781
impl<T> EraseType for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
7882
type Result = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
7983
}

compiler/rustc_middle/src/query/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1953,7 +1953,7 @@ rustc_queries! {
19531953
desc { "normalizing `{}`", goal.value }
19541954
}
19551955

1956-
query implied_outlives_bounds(
1956+
query implied_outlives_bounds_compat(
19571957
goal: CanonicalTyGoal<'tcx>
19581958
) -> Result<
19591959
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
@@ -1962,6 +1962,15 @@ rustc_queries! {
19621962
desc { "computing implied outlives bounds for `{}`", goal.value.value }
19631963
}
19641964

1965+
query implied_outlives_bounds(
1966+
goal: CanonicalTyGoal<'tcx>
1967+
) -> Result<
1968+
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
1969+
NoSolution,
1970+
> {
1971+
desc { "computing implied outlives bounds v2 for `{}`", goal.value.value }
1972+
}
1973+
19651974
/// Do not call this query directly:
19661975
/// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
19671976
query dropck_outlives(

compiler/rustc_middle/src/traits/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ pub struct NormalizationResult<'tcx> {
191191
/// case they are called implied bounds). They are fed to the
192192
/// `OutlivesEnv` which in turn is supplied to the region checker and
193193
/// other parts of the inference system.
194-
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
194+
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
195195
pub enum OutlivesBound<'tcx> {
196196
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
197197
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),

compiler/rustc_trait_selection/src/traits/misc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ pub fn all_fields_implement_trait<'tcx>(
191191
// Check regions assuming the self type of the impl is WF
192192
let outlives_env = OutlivesEnvironment::with_bounds(
193193
param_env,
194-
infcx.implied_bounds_tys(
194+
infcx.implied_bounds_tys_compat(
195195
param_env,
196196
parent_cause.body_id,
197-
FxIndexSet::from_iter([self_type]),
197+
&FxIndexSet::from_iter([self_type]),
198198
),
199199
);
200200
let errors = infcx.resolve_regions(&outlives_env);

0 commit comments

Comments
 (0)