Skip to content

Commit

Permalink
Auto merge of rust-lang#120649 - matthiaskrgr:rollup-ek80j61, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#119759 (Add FileCheck annotations to dataflow-const-prop tests)
 - rust-lang#120323 (On E0277 be clearer about implicit `Sized` bounds on type params and assoc types)
 - rust-lang#120473 (Only suggest removal of `as_*` and `to_` conversion methods on E0308)
 - rust-lang#120540 (add test for try-block-in-match-arm)
 - rust-lang#120547 (`#![feature(inline_const_pat)]` is no longer incomplete)
 - rust-lang#120552 (Correctly check `never_type` feature gating)
 - rust-lang#120555 (put pnkfelix (me) back on the review queue.)
 - rust-lang#120556 (Improve the diagnostics for unused generic parameters)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Feb 4, 2024
2 parents 268dbbb + 7fa99bf commit 4d87c4a
Show file tree
Hide file tree
Showing 161 changed files with 1,151 additions and 541 deletions.
13 changes: 13 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Expand Up @@ -362,6 +362,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}

fn visit_generic_args(&mut self, args: &'a ast::GenericArgs) {
// This check needs to happen here because the never type can be returned from a function,
// but cannot be used in any other context. If this check was in `visit_fn_ret_ty`, it
// include both functions and generics like `impl Fn() -> !`.
if let ast::GenericArgs::Parenthesized(generic_args) = args
&& let ast::FnRetTy::Ty(ref ty) = generic_args.output
&& matches!(ty.kind, ast::TyKind::Never)
{
gate!(&self, never_type, ty.span, "the `!` type is experimental");
}
visit::walk_generic_args(self, args);
}

fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind {
ast::ExprKind::TryBlock(_) => {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_error_codes/src/error_codes/E0091.md
@@ -1,11 +1,11 @@
An unnecessary type or const parameter was given in a type alias.
An unnecessary type parameter was given in a type alias.

Erroneous code example:

```compile_fail,E0091
type Foo<T> = u32; // error: type parameter `T` is unused
type Foo<T> = u32; // error: type parameter `T` is never used
// or:
type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
type Foo<A, B> = Box<A>; // error: type parameter `B` is never used
```

Please check you didn't write too many parameters. Example:
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/unstable.rs
Expand Up @@ -496,7 +496,7 @@ declare_features! (
/// Allow anonymous constants from an inline `const` block
(unstable, inline_const, "1.49.0", Some(76001)),
/// Allow anonymous constants from an inline `const` block in pattern position
(incomplete, inline_const_pat, "1.58.0", Some(76001)),
(unstable, inline_const_pat, "1.58.0", Some(76001)),
/// Allows using `pointer` and `reference` in intra-doc links
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
// Allows setting the threshold for the `large_assignments` lint.
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Expand Up @@ -434,6 +434,17 @@ hir_analysis_unused_associated_type_bounds =
.note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
.suggestion = remove this bound
hir_analysis_unused_generic_parameter =
{$param_def_kind} `{$param_name}` is never used
.label = unused {$param_def_kind}
.const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
hir_analysis_unused_generic_parameter_adt_help =
consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
consider removing `{$param_name}` or referring to it in a field
hir_analysis_unused_generic_parameter_ty_alias_help =
consider removing `{$param_name}` or referring to it in the body of the type alias
hir_analysis_value_of_associated_struct_already_specified =
the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
.label = re-bound here
Expand Down
14 changes: 11 additions & 3 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Expand Up @@ -28,6 +28,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_negative_sized_bound = false;
let mut seen_positive_sized_bound = false;

// Try to find an unbound in bounds.
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
Expand All @@ -45,6 +46,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
seen_negative_sized_bound = true;
}
}
hir::TraitBoundModifier::None => {
if let Some(sized_def_id) = sized_def_id
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_positive_sized_bound = true;
}
}
_ => {}
}
}
Expand Down Expand Up @@ -82,11 +90,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
);
}

if seen_sized_unbound || seen_negative_sized_bound {
// There was in fact a `?Sized` or `!Sized` bound;
if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
// There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
// we don't need to do anything.
} else if sized_def_id.is_some() {
// There was no `?Sized` or `!Sized` bound;
// There was no `?Sized`, `!Sized` or explicit `Sized` bound;
// add `Sized` if it's available.
bounds.push_sized(tcx, self_ty, span);
}
Expand Down
77 changes: 54 additions & 23 deletions compiler/rustc_hir_analysis/src/check/check.rs
Expand Up @@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
use rustc_type_ir::fold::TypeFoldable;

use std::cell::LazyCell;
use std::ops::ControlFlow;

pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
Expand Down Expand Up @@ -520,9 +521,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}
}
DefKind::TyAlias => {
let pty_ty = tcx.type_of(def_id).instantiate_identity();
let generics = tcx.generics_of(def_id);
check_type_params_are_used(tcx, generics, pty_ty);
check_type_alias_type_params_are_used(tcx, def_id);
}
DefKind::ForeignMod => {
let it = tcx.hir().expect_item(def_id);
Expand Down Expand Up @@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
}

pub(super) fn check_type_params_are_used<'tcx>(
tcx: TyCtxt<'tcx>,
generics: &ty::Generics,
ty: Ty<'tcx>,
) {
debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);

assert_eq!(generics.parent, None);
fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
if tcx.type_alias_is_lazy(def_id) {
// Since we compute the variances for lazy type aliases and already reject bivariant
// parameters as unused, we can and should skip this check for lazy type aliases.
return;
}

let generics = tcx.generics_of(def_id);
if generics.own_counts().types == 0 {
return;
}

let mut params_used = BitSet::new_empty(generics.params.len());

let ty = tcx.type_of(def_id).instantiate_identity();
if ty.references_error() {
// If there is already another error, do not emit
// an error for not using a type parameter.
// If there is already another error, do not emit an error for not using a type parameter.
assert!(tcx.dcx().has_errors().is_some());
return;
}

// Lazily calculated because it is only needed in case of an error.
let bounded_params = LazyCell::new(|| {
tcx.explicit_predicates_of(def_id)
.predicates
.iter()
.filter_map(|(predicate, span)| {
let bounded_ty = match predicate.kind().skip_binder() {
ty::ClauseKind::Trait(pred) => pred.trait_ref.self_ty(),
ty::ClauseKind::TypeOutlives(pred) => pred.0,
_ => return None,
};
if let ty::Param(param) = bounded_ty.kind() {
Some((param.index, span))
} else {
None
}
})
// FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
// time of writing). This is a bit fragile since we later use the span to detect elaborated
// `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
// since it would overwrite the span of the user-written bound. This could be fixed by
// folding the spans with `Span::to` which requires a bit of effort I think.
.collect::<FxHashMap<_, _>>()
});

let mut params_used = BitSet::new_empty(generics.params.len());
for leaf in ty.walk() {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
&& let ty::Param(param) = leaf_ty.kind()
Expand All @@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>(
&& let ty::GenericParamDefKind::Type { .. } = param.kind
{
let span = tcx.def_span(param.def_id);
struct_span_code_err!(
tcx.dcx(),
let param_name = Ident::new(param.name, span);

// The corresponding predicates are post-`Sized`-elaboration. Therefore we
// * check for emptiness to detect lone user-written `?Sized` bounds
// * compare the param span to the pred span to detect lone user-written `Sized` bounds
let has_explicit_bounds = bounded_params.is_empty()
|| (*bounded_params).get(&param.index).is_some_and(|&&pred_sp| pred_sp != span);
let const_param_help = (!has_explicit_bounds).then_some(());

let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
span,
E0091,
"type parameter `{}` is unused",
param.name,
)
.with_span_label(span, "unused type parameter")
.emit();
param_name,
param_def_kind: tcx.def_descr(param.def_id),
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
const_param_help,
});
diag.code(E0091);
diag.emit();
}
}
}
Expand Down
64 changes: 33 additions & 31 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,11 +1,10 @@
use crate::autoderef::Autoderef;
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use crate::errors;

use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{
codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::lang_items::LangItem;
Expand All @@ -21,7 +20,7 @@ use rustc_middle::ty::{
};
use rustc_middle::ty::{GenericArgKind, GenericArgs};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::regions::InferCtxtRegionExt;
Expand Down Expand Up @@ -1869,7 +1868,7 @@ fn check_variances_for_type_defn<'tcx>(
hir::ParamName::Error => {}
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
report_bivariance(tcx, hir_param, has_explicit_bounds);
report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind);
}
}
}
Expand All @@ -1879,30 +1878,38 @@ fn report_bivariance(
tcx: TyCtxt<'_>,
param: &rustc_hir::GenericParam<'_>,
has_explicit_bounds: bool,
item_kind: ItemKind<'_>,
) -> ErrorGuaranteed {
let span = param.span;
let param_name = param.name.ident().name;
let mut err = error_392(tcx, span, param_name);

let suggested_marker_id = tcx.lang_items().phantom_data();
// Help is available only in presence of lang items.
let msg = if let Some(def_id) = suggested_marker_id {
format!(
"consider removing `{}`, referring to it in a field, or using a marker such as `{}`",
param_name,
tcx.def_path_str(def_id),
)
} else {
format!("consider removing `{param_name}` or referring to it in a field")
let param_name = param.name.ident();

let help = match item_kind {
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
if let Some(def_id) = tcx.lang_items().phantom_data() {
errors::UnusedGenericParameterHelp::Adt {
param_name,
phantom_data: tcx.def_path_str(def_id),
}
} else {
errors::UnusedGenericParameterHelp::AdtNoPhantomData { param_name }
}
}
ItemKind::TyAlias(..) => errors::UnusedGenericParameterHelp::TyAlias { param_name },
item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"),
};
err.help(msg);

if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
err.help(format!(
"if you intended `{param_name}` to be a const parameter, use `const {param_name}: usize` instead"
));
}
err.emit()
let const_param_help =
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
.then_some(());

let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
span: param.span,
param_name,
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
help,
const_param_help,
});
diag.code(E0392);
diag.emit()
}

impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
Expand Down Expand Up @@ -1967,11 +1974,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
res
}

fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
struct_span_code_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used")
.with_span_label(span, "unused parameter")
}

pub fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
}
24 changes: 24 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Expand Up @@ -1511,3 +1511,27 @@ pub struct NotSupportedDelegation<'a> {
#[label]
pub callee_span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_unused_generic_parameter)]
pub(crate) struct UnusedGenericParameter {
#[primary_span]
#[label]
pub span: Span,
pub param_name: Ident,
pub param_def_kind: &'static str,
#[subdiagnostic]
pub help: UnusedGenericParameterHelp,
#[help(hir_analysis_const_param_help)]
pub const_param_help: Option<()>,
}

#[derive(Subdiagnostic)]
pub(crate) enum UnusedGenericParameterHelp {
#[help(hir_analysis_unused_generic_parameter_adt_help)]
Adt { param_name: Ident, phantom_data: String },
#[help(hir_analysis_unused_generic_parameter_adt_no_phantom_data_help)]
AdtNoPhantomData { param_name: Ident },
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
TyAlias { param_name: Ident },
}
2 changes: 2 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Expand Up @@ -261,6 +261,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr.kind
&& let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr)
&& self.can_coerce(recv_ty, expected)
&& let name = method.name.as_str()
&& (name.starts_with("to_") || name.starts_with("as_") || name == "into")
{
let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) {
expr.span.with_lo(recv_span.hi())
Expand Down

0 comments on commit 4d87c4a

Please sign in to comment.