From 3799af3337d748647ca6c4abbad63975275a7a37 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 21 Sep 2023 17:14:58 -0700 Subject: [PATCH 1/2] diagnostics: avoid mismatch between variance index and hir generic This happens because variances are constructed from ty generics, and ty generics are always constructed with lifetimes first. See compiler/rustc_hir_analysis/src/collect/generics_of.rs:248-269 Fixes #83556 --- .../rustc_hir_analysis/src/check/wfcheck.rs | 27 ++++++++++++++++--- tests/ui/generics/issue-83556.rs | 5 ++++ tests/ui/generics/issue-83556.stderr | 18 +++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 tests/ui/generics/issue-83556.rs create mode 100644 tests/ui/generics/issue-83556.stderr diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b97e0a80fe6c9..412b03b3be335 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1755,6 +1755,8 @@ fn check_variances_for_type_defn<'tcx>( .collect::>() }); + let ty_generics = tcx.generics_of(item.owner_id); + for (index, _) in variances.iter().enumerate() { let parameter = Parameter(index as u32); @@ -1762,13 +1764,32 @@ fn check_variances_for_type_defn<'tcx>( continue; } - let param = &hir_generics.params[index]; + let ty_param = &ty_generics.params[index]; + let mut hir_param = &hir_generics.params[index]; + + if ty_param.name != hir_param.name.ident().name { + // valid programs always have lifetimes before types in the generic parameter list + // ty_generics are normalized to be in this required order, and variances are built + // from ty generics, not from hir generics. but we need hir generics to get + // a span out + // + // if they aren't in the same order, then the user has written invalid code, and already + // got an error about it (or I'm wrong about this) + tcx.sess + .delay_span_bug(hir_param.span, "hir generics and ty generics in different order"); + for hp in hir_generics.params { + if hp.name.ident().name == ty_param.name { + hir_param = hp; + break; + } + } + } - match param.name { + match hir_param.name { hir::ParamName::Error => {} _ => { let has_explicit_bounds = explicitly_bounded_params.contains(¶meter); - report_bivariance(tcx, param, has_explicit_bounds); + report_bivariance(tcx, hir_param, has_explicit_bounds); } } } diff --git a/tests/ui/generics/issue-83556.rs b/tests/ui/generics/issue-83556.rs new file mode 100644 index 0000000000000..21f801d9d1067 --- /dev/null +++ b/tests/ui/generics/issue-83556.rs @@ -0,0 +1,5 @@ +struct Foo(&'a ()); +//~^ ERROR lifetime parameters must be declared prior to +//~| ERROR parameter `T` is never used + +fn main() {} diff --git a/tests/ui/generics/issue-83556.stderr b/tests/ui/generics/issue-83556.stderr new file mode 100644 index 0000000000000..2ed999510eb71 --- /dev/null +++ b/tests/ui/generics/issue-83556.stderr @@ -0,0 +1,18 @@ +error: lifetime parameters must be declared prior to type and const parameters + --> $DIR/issue-83556.rs:1:15 + | +LL | struct Foo(&'a ()); + | ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>` + +error[E0392]: parameter `T` is never used + --> $DIR/issue-83556.rs:1:12 + | +LL | struct Foo(&'a ()); + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: usize` instead + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0392`. From 58ef3a0ec9a3e2151a103964683b5d00932304d8 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 22 Sep 2023 22:41:01 -0700 Subject: [PATCH 2/2] diagnostics: simpler 83556 handling by bailing out --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 11 +++-------- tests/ui/generics/issue-83556.rs | 1 - tests/ui/generics/issue-83556.stderr | 12 +----------- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 412b03b3be335..00a684f296325 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1765,9 +1765,9 @@ fn check_variances_for_type_defn<'tcx>( } let ty_param = &ty_generics.params[index]; - let mut hir_param = &hir_generics.params[index]; + let hir_param = &hir_generics.params[index]; - if ty_param.name != hir_param.name.ident().name { + if ty_param.def_id != hir_param.def_id.into() { // valid programs always have lifetimes before types in the generic parameter list // ty_generics are normalized to be in this required order, and variances are built // from ty generics, not from hir generics. but we need hir generics to get @@ -1777,12 +1777,7 @@ fn check_variances_for_type_defn<'tcx>( // got an error about it (or I'm wrong about this) tcx.sess .delay_span_bug(hir_param.span, "hir generics and ty generics in different order"); - for hp in hir_generics.params { - if hp.name.ident().name == ty_param.name { - hir_param = hp; - break; - } - } + continue; } match hir_param.name { diff --git a/tests/ui/generics/issue-83556.rs b/tests/ui/generics/issue-83556.rs index 21f801d9d1067..7cea1c8631fe9 100644 --- a/tests/ui/generics/issue-83556.rs +++ b/tests/ui/generics/issue-83556.rs @@ -1,5 +1,4 @@ struct Foo(&'a ()); //~^ ERROR lifetime parameters must be declared prior to -//~| ERROR parameter `T` is never used fn main() {} diff --git a/tests/ui/generics/issue-83556.stderr b/tests/ui/generics/issue-83556.stderr index 2ed999510eb71..93affaffe60c3 100644 --- a/tests/ui/generics/issue-83556.stderr +++ b/tests/ui/generics/issue-83556.stderr @@ -4,15 +4,5 @@ error: lifetime parameters must be declared prior to type and const parameters LL | struct Foo(&'a ()); | ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>` -error[E0392]: parameter `T` is never used - --> $DIR/issue-83556.rs:1:12 - | -LL | struct Foo(&'a ()); - | ^ unused parameter - | - = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0392`.