Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::process::ExitStatus;

use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg,
Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg,
Level, msg,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::layout::LayoutError;
Expand Down Expand Up @@ -1249,20 +1250,29 @@ pub(crate) struct FeatureNotValid<'a> {
#[label("`{$feature}` is not valid for this target")]
pub span: Span,
#[subdiagnostic]
pub plus_hint: Option<RemovePlusFromFeatureName<'a>>,
pub hint: FeatureNotValidHint<'a>,
}

#[derive(Subdiagnostic)]
#[suggestion(
"consider removing the leading `+` in the feature name",
code = "enable = \"{stripped}\"",
applicability = "maybe-incorrect",
style = "verbose"
)]
pub struct RemovePlusFromFeatureName<'a> {
#[primary_span]
pub span: Span,
pub stripped: &'a str,
pub(crate) enum FeatureNotValidHint<'a> {
#[suggestion(
"consider removing the leading `+` in the feature name",
code = "enable = \"{stripped}\"",
applicability = "maybe-incorrect",
style = "verbose"
)]
RemovePlusFromFeatureName {
#[primary_span]
span: Span,
stripped: &'a str,
},
#[help(
"valid names are: {$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize },
}

#[derive(Diagnostic)]
Expand Down
32 changes: 21 additions & 11 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, Symbol, edit_distance, sym};
use rustc_target::spec::Arch;
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
use smallvec::SmallVec;

use crate::errors::{FeatureNotValid, RemovePlusFromFeatureName};
use crate::errors::{FeatureNotValid, FeatureNotValidHint};
use crate::{errors, target_features};

/// Compute the enabled target features from the `#[target_feature]` function attribute.
Expand All @@ -32,15 +32,25 @@ pub(crate) fn from_target_feature_attr(
for &(feature, feature_span) in features {
let feature_str = feature.as_str();
let Some(stability) = rust_target_features.get(feature_str) else {
let plus_hint = feature_str
.strip_prefix('+')
.filter(|stripped| rust_target_features.contains_key(*stripped))
.map(|stripped| RemovePlusFromFeatureName { span: feature_span, stripped });
tcx.dcx().emit_err(FeatureNotValid {
feature: feature_str,
span: feature_span,
plus_hint,
});
let hint = if let Some(stripped) = feature_str.strip_prefix('+')
&& rust_target_features.contains_key(stripped)
{
FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped }
} else {
// Show the 5 feature names that are most similar to the input.
let mut valid_names: Vec<_> =
rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord();
valid_names.sort_by_key(|name| {
edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX)
});
valid_names.truncate(5);

FeatureNotValidHint::ValidFeatureNames {
possibilities: valid_names.into(),
and_more: rust_target_features.len().saturating_sub(5),
}
};
tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint });
continue;
};

Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ impl Suggestions {
Suggestions::Disabled => Vec::new(),
}
}

pub fn len(&self) -> usize {
match self {
Suggestions::Enabled(suggestions) => suggestions.len(),
Suggestions::Sealed(suggestions) => suggestions.len(),
Suggestions::Disabled => 0,
}
}
}

impl Default for Suggestions {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ordered_associated_items.extend(
tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order()
// Only associated types & consts can possibly be constrained via a binding.
.filter(|item| item.is_type() || item.is_const())
// Only associated types & type consts can possibly be
// constrained in a trait object type via a binding.
.filter(|item| item.is_type() || item.is_type_const())
// Traits with RPITITs are simply not dyn compatible (for now).
.filter(|item| !item.is_impl_trait_in_trait())
.map(|item| (item.def_id, trait_ref)),
Expand Down
124 changes: 66 additions & 58 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1636,69 +1636,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
};

if let Some(span) = self.tcx.hir_res_span(pat_res) {
let span = match (self.tcx.hir_res_span(pat_res), res.opt_def_id()) {
(Some(span), _) => span,
(None, Some(def_id)) => self.tcx.def_span(def_id),
(None, None) => {
e.emit();
return;
}
};
if let [hir::PathSegment { ident, args: None, .. }] = segments
&& e.suggestions.len() == 0
{
e.span_label(span, format!("{} defined here", res.descr()));
if let [hir::PathSegment { ident, .. }] = segments {
e.span_label(
pat_span,
format!(
"`{}` is interpreted as {} {}, not a new binding",
ident,
res.article(),
res.descr(),
),
);
match self.tcx.parent_hir_node(hir_id) {
hir::Node::PatField(..) => {
e.span_label(
pat_span,
format!(
"`{}` is interpreted as {} {}, not a new binding",
ident,
res.article(),
res.descr(),
),
);
match self.tcx.parent_hir_node(hir_id) {
hir::Node::PatField(..) => {
e.span_suggestion_verbose(
ident.span.shrink_to_hi(),
"bind the struct field to a different name instead",
format!(": other_{}", ident.as_str().to_lowercase()),
Applicability::HasPlaceholders,
);
}
_ => {
let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
ty::Adt(def, _) => match res {
Res::Def(DefKind::Const { .. }, def_id) => {
(Some(def.did()), Some(def_id))
}
_ => (None, None),
},
_ => (None, None),
};

let is_range = matches!(
type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
Some(
LangItem::Range
| LangItem::RangeFrom
| LangItem::RangeTo
| LangItem::RangeFull
| LangItem::RangeInclusiveStruct
| LangItem::RangeToInclusive,
)
);
if is_range {
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
let msg = "constants only support matching by type, \
if you meant to match against a range of values, \
consider using a range pattern like `min ..= max` in the match block";
e.note(msg);
}
} else {
let msg = "introduce a new binding instead";
let sugg = format!("other_{}", ident.as_str().to_lowercase());
e.span_suggestion_verbose(
ident.span.shrink_to_hi(),
"bind the struct field to a different name instead",
format!(": other_{}", ident.as_str().to_lowercase()),
ident.span,
msg,
sugg,
Applicability::HasPlaceholders,
);
}
_ => {
let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
ty::Adt(def, _) => match res {
Res::Def(DefKind::Const { .. }, def_id) => {
(Some(def.did()), Some(def_id))
}
_ => (None, None),
},
_ => (None, None),
};

let is_range = matches!(
type_def_id.and_then(|id| self.tcx.as_lang_item(id)),
Some(
LangItem::Range
| LangItem::RangeFrom
| LangItem::RangeTo
| LangItem::RangeFull
| LangItem::RangeInclusiveStruct
| LangItem::RangeToInclusive,
)
);
if is_range {
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
let msg = "constants only support matching by type, \
if you meant to match against a range of values, \
consider using a range pattern like `min ..= max` in the match block";
e.note(msg);
}
} else {
let msg = "introduce a new binding instead";
let sugg = format!("other_{}", ident.as_str().to_lowercase());
e.span_suggestion(
ident.span,
msg,
sugg,
Applicability::HasPlaceholders,
);
}
}
};
}
}
};
}
e.emit();
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/assoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ impl AssocItem {
self.kind.as_def_kind()
}

pub fn is_const(&self) -> bool {
matches!(self.kind, ty::AssocKind::Const { .. })
pub fn is_type_const(&self) -> bool {
matches!(self.kind, ty::AssocKind::Const { is_type_const: true, .. })
}

pub fn is_fn(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ impl<'tcx> Ty<'tcx> {
.map(|principal| {
tcx.associated_items(principal.def_id())
.in_definition_order()
.filter(|item| item.is_type() || item.is_const())
.filter(|item| item.is_type() || item.is_type_const())
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.count()
Expand Down
30 changes: 6 additions & 24 deletions compiler/rustc_query_impl/src/from_cycle_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_middle::bug;
use rustc_middle::dep_graph::DepKind;
use rustc_middle::queries::{QueryVTables, TaggedQueryKey};
use rustc_middle::query::CycleError;
use rustc_middle::query::erase::erase_val;
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{ErrorGuaranteed, Span};

Expand All @@ -32,9 +32,9 @@ pub(crate) fn specialize_query_vtables<'tcx>(vtables: &mut QueryVTables<'tcx>) {
vtables.check_representability_adt_ty.value_from_cycle_error =
|tcx, _, cycle, _err| check_representability(tcx, cycle);

vtables.variances_of.value_from_cycle_error = |tcx, _, cycle, err| {
vtables.variances_of.value_from_cycle_error = |tcx, key, _, err| {
let _guar = err.delay_as_bug();
erase_val(variances_of(tcx, cycle))
erase_val(variances_of(tcx, key))
};

vtables.layout_of.value_from_cycle_error = |tcx, _, cycle, err| {
Expand Down Expand Up @@ -105,27 +105,9 @@ fn check_representability<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>
guar.raise_fatal()
}

fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, cycle_error: CycleError<'tcx>) -> &'tcx [ty::Variance] {
search_for_cycle_permutation(
&cycle_error.cycle,
|cycle| {
if let Some(frame) = cycle.get(0)
&& frame.node.dep_kind == DepKind::variances_of
&& let Some(def_id) = frame.node.def_id
{
let n = tcx.generics_of(def_id).own_params.len();
ControlFlow::Break(tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n)))
} else {
ControlFlow::Continue(())
}
},
|| {
span_bug!(
cycle_error.usage.as_ref().unwrap().span,
"only `variances_of` returns `&[ty::Variance]`"
)
},
)
fn variances_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx [ty::Variance] {
let n = tcx.generics_of(def_id).own_params.len();
tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))
}

// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
.flat_map(|super_poly_trait_ref| {
tcx.associated_items(super_poly_trait_ref.def_id())
.in_definition_order()
.filter(|item| item.is_type() || item.is_const())
.filter(|item| item.is_type() || item.is_type_const())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(move |assoc_item| {
super_poly_trait_ref.map_bound(|super_trait_ref| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,13 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
// Don't suggest constraining a projection to something
// containing itself, e.g. `Item = &<I as Iterator>::Item`.
(_, ty::Alias(ty::Projection | ty::Inherent, proj_ty))
if !tcx.is_impl_trait_in_trait(proj_ty.def_id) =>
if !tcx.is_impl_trait_in_trait(proj_ty.def_id)
&& !tcx
.erase_and_anonymize_regions(values.expected)
.contains(tcx.erase_and_anonymize_regions(values.found)) =>
{
let msg = || {
format!(
Expand Down
4 changes: 2 additions & 2 deletions src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ RUN sh /scripts/sccache.sh
ENV NO_DEBUG_ASSERTIONS=1
ENV NO_OVERFLOW_CHECKS=1

ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check-aux
ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu"
ENV RUST_CHECK_TARGET="check-aux"
Loading
Loading