Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1982d87
Merge commit '3383cfbd3572465febc7a8f816a46304373de46a' into sync-fro…
calebzulawski Jan 18, 2025
02a28b2
Remove ignored `#[must_use]` attributes from portable-simd
samueltardieu Feb 12, 2025
aaf8ff1
Merge commit 'c14f2fc3eb69c164d8bf8d36d91ebd60bd5261e6' into sync-fro…
calebzulawski Mar 19, 2025
0f6f7d1
Merge branch 'rust-upstream-2025-03-20' into sync-from-rust-2025-03-20
calebzulawski Mar 20, 2025
e8b522d
Merge pull request #457 from rust-lang/sync-from-rust-2025-03-20
calebzulawski Mar 22, 2025
cdac23c
Fix grammar in beginners-guide.md
corneliusroemer Apr 7, 2025
6894761
Merge pull request #458 from corneliusroemer/patch-1
programmerjake Apr 7, 2025
6951b68
Remove usize/isize `From` impls for vendor vector types
okaneco Jun 11, 2025
70b1c20
Merge pull request #464 from okaneco/remove_from_usize_impls
calebzulawski Jun 11, 2025
97a3a50
Add const to as_mut_array, copy_to_slice
clarfonthey Jun 12, 2025
7a0cc2f
Merge pull request #465 from clarfonthey/const-mut
calebzulawski Jun 12, 2025
a857909
Make Mask::splat const
clarfonthey Jun 13, 2025
704a1a9
Merge pull request #466 from clarfonthey/const-mask-splat
calebzulawski Jun 13, 2025
b47a091
clippy fix: use div_ceil
hkBst Jul 4, 2025
5a26848
use `div_ceil` instead of manual logic
folkertdev Jul 5, 2025
3439347
Merge pull request #468 from hkBst/div-ceil
calebzulawski Jul 5, 2025
3a0909c
Fix incorrect reference to EMPTY_BIT_MASK
burgerindividual Aug 4, 2025
f560820
Merge pull request #471 from burgerindividual/fix-avx512
calebzulawski Aug 4, 2025
3f01c75
Update nightly toolchain and fix broken examples
okaneco Aug 18, 2025
28e79b1
Update Cargo.lock
okaneco Aug 18, 2025
07e9de0
Remove `i586-pc-windows-msvc` from CI
okaneco Aug 18, 2025
323484c
Add no-extra-rounding-error flag to Miri CI config
okaneco Aug 18, 2025
c43c8d2
Check some float ops approximately
calebzulawski Aug 18, 2025
b902397
Clippy isn't aware of repr(simd, packed)
calebzulawski Aug 18, 2025
1ce33dd
Revert "Add no-extra-rounding-error flag to Miri CI config"
calebzulawski Aug 18, 2025
a645554
Merge pull request #473 from okaneco/array_fix
calebzulawski Aug 18, 2025
61c45c1
loongarch64: Use unified data types for SIMD intrinsics
heiher Aug 8, 2025
295ba3b
Merge pull request #476 from heiher/loong-simd-types
calebzulawski Aug 26, 2025
402c045
docs(std): add missing closing code block fences in doc comments
AudaciousAxiom Sep 2, 2025
1e62d4c
Rename `Mask::to_int` to `Mask::to_simd`
okaneco Sep 5, 2025
42409f0
Rename `Mask::from_int` to `Mask::from_simd`
okaneco Sep 5, 2025
3a70dd6
Rename `Mask::from_int_unchecked` to `Mask::from_simd_unchecked`
okaneco Sep 5, 2025
936d58b
Merge pull request #478 from okaneco/rename_mask_int_to_simd
calebzulawski Sep 5, 2025
32ba8ed
Remove poor-performing bitmasks, add Select trait, and enable select …
calebzulawski Sep 13, 2025
8ce88bc
Remove LaneCount in favor of #[rustc_simd_monomorphize_lane_limit] at…
calebzulawski Oct 7, 2025
061617b
Add alignment parameter to `simd_masked_{load,store}`
sayantn Oct 8, 2025
242b4b5
Remove more #[must_use] from portable-simd
dtolnay Nov 11, 2025
4215b72
removal of aarch64 special-casing (#497)
kolektiv Dec 11, 2025
e86cfa0
add foregin type tests
KaiTomotake Jan 22, 2026
7b6f82e
use `intrinsics::simd::simd_splat`
folkertdev Jan 26, 2026
e3d85fb
Merge pull request #501 from folkertdev/simd-splat-intrinsic
programmerjake Jan 26, 2026
b3e93fc
use `cargo miri nextest` to parallelize miri tests
folkertdev Jan 26, 2026
808d349
experiment with cargo nextest partitions
folkertdev Jan 26, 2026
d9a7c40
Merge pull request #502 from folkertdev/miri-nextest
programmerjake Jan 27, 2026
b32dd9b
Merge branch 'rust-upstream-2026-01-27' into sync-from-rust-2026-01-27
folkertdev Jan 27, 2026
324e366
remove usage of `stdarch_x86_avx512` which is now stable
folkertdev Jan 27, 2026
d9aae8c
Merge pull request #503 from folkertdev/sync-from-rust-2026-01-27
calebzulawski Jan 28, 2026
0eaef59
Merge commit 'd9aae8cc544c5f524a12b5f3b2f3c3745c34dd74' into sync-fro…
calebzulawski Jan 28, 2026
fb995ef
test(frontmatter): Show behavior for straw cr
epage Dec 9, 2025
e912248
refactor(parse): Be consistent in naming
epage Dec 9, 2025
053b947
refactor(parse): Consistently use real_s
epage Dec 9, 2025
dd55392
refactor(parse): Use a common frame of reference
epage Dec 9, 2025
52d4ef1
fix(parser): Disallow CR in frontmatter
epage Dec 9, 2025
9e61014
Convert `parse_nested_meta` to `parse_args_with` for `#[diagnostic]`
JonathanBrouwer Jan 28, 2026
5d21a21
Convert `parse_nested_meta` to `parse_args_with` for `#[subdiagnostic]`
JonathanBrouwer Jan 28, 2026
0bf3f5d
Remove unused `no_span` option
JonathanBrouwer Jan 25, 2026
2e8347a
Remove `HasFieldMap` trait in favour of passing `FieldMap` directly
JonathanBrouwer Jan 28, 2026
b71ff51
Update std and tests to match std::simd API (remove LaneCount bound a…
calebzulawski Jan 28, 2026
4b22ee9
Tweak E0599 to consolidate unsatisfied trait bound messages
JohnTitor Jan 22, 2026
d49f50f
Rollup merge of #151775 - calebzulawski:sync-from-portable-simd-2026-…
Zalathar Jan 29, 2026
2b899b0
Rollup merge of #151488 - JohnTitor:issue-114430, r=estebank
Zalathar Jan 29, 2026
b6ce0c0
Rollup merge of #149823 - epage:f, r=Kivooeo
Zalathar Jan 29, 2026
36a2726
Rollup merge of #151475 - KaiTomotake:add-foreign-type-tests, r=Kivooeo
Zalathar Jan 29, 2026
617288e
Rollup merge of #151657 - JonathanBrouwer:diag2, r=Kivooeo
Zalathar Jan 29, 2026
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
145 changes: 142 additions & 3 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
use rustc_errors::{
Applicability, Diag, MultiSpan, StashKey, listify, pluralize, struct_span_code_err,
};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -50,6 +52,51 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
use crate::method::probe::UnsatisfiedPredicates;
use crate::{Expectation, FnCtxt};

/// Tracks trait bounds and detects duplicates between ref and non-ref versions of self types.
/// This is used to condense error messages when the same trait bound appears for both
/// `T` and `&T` (or `&mut T`).
struct TraitBoundDuplicateTracker {
trait_def_ids: FxIndexSet<DefId>,
seen_ref: FxIndexSet<DefId>,
seen_non_ref: FxIndexSet<DefId>,
has_ref_dupes: bool,
}

impl TraitBoundDuplicateTracker {
fn new() -> Self {
Self {
trait_def_ids: FxIndexSet::default(),
seen_ref: FxIndexSet::default(),
seen_non_ref: FxIndexSet::default(),
has_ref_dupes: false,
}
}

/// Track a trait bound. `is_ref` indicates whether the self type is a reference.
fn track(&mut self, def_id: DefId, is_ref: bool) {
self.trait_def_ids.insert(def_id);
if is_ref {
if self.seen_non_ref.contains(&def_id) {
self.has_ref_dupes = true;
}
self.seen_ref.insert(def_id);
} else {
if self.seen_ref.contains(&def_id) {
self.has_ref_dupes = true;
}
self.seen_non_ref.insert(def_id);
}
}

fn has_ref_dupes(&self) -> bool {
self.has_ref_dupes
}

fn into_trait_def_ids(self) -> FxIndexSet<DefId> {
self.trait_def_ids
}
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_slice_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
self.autoderef(span, ty)
Expand Down Expand Up @@ -1004,6 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_ident: Ident,
item_kind: &str,
bound_spans: SortedMap<Span, Vec<String>>,
unsatisfied_predicates: &UnsatisfiedPredicates<'tcx>,
) {
let mut ty_span = match rcvr_ty.kind() {
ty::Param(param_type) => {
Expand All @@ -1012,13 +1060,61 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Adt(def, _) if def.did().is_local() => Some(self.tcx.def_span(def.did())),
_ => None,
};
let rcvr_ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
let mut tracker = TraitBoundDuplicateTracker::new();
for (predicate, _parent_pred, _cause) in unsatisfied_predicates {
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
predicate.kind().skip_binder()
&& let self_ty = pred.trait_ref.self_ty()
&& self_ty.peel_refs() == rcvr_ty
{
let is_ref = matches!(self_ty.kind(), ty::Ref(..));
tracker.track(pred.trait_ref.def_id, is_ref);
}
}
let has_ref_dupes = tracker.has_ref_dupes();
let mut missing_trait_names = tracker
.into_trait_def_ids()
.into_iter()
.map(|def_id| format!("`{}`", self.tcx.def_path_str(def_id)))
.collect::<Vec<_>>();
missing_trait_names.sort();
let should_condense =
has_ref_dupes && missing_trait_names.len() > 1 && matches!(rcvr_ty.kind(), ty::Adt(..));
let missing_trait_list = if should_condense {
Some(match missing_trait_names.as_slice() {
[only] => only.clone(),
[first, second] => format!("{first} or {second}"),
[rest @ .., last] => format!("{} or {last}", rest.join(", ")),
[] => String::new(),
})
} else {
None
};
for (span, mut bounds) in bound_spans {
if !self.tcx.sess.source_map().is_span_accessible(span) {
continue;
}
bounds.sort();
bounds.dedup();
let pre = if Some(span) == ty_span {
let is_ty_span = Some(span) == ty_span;
if is_ty_span && should_condense {
ty_span.take();
let label = if let Some(missing_trait_list) = &missing_trait_list {
format!(
"{item_kind} `{item_ident}` not found for this {} because `{rcvr_ty_str}` doesn't implement {missing_trait_list}",
rcvr_ty.prefix_string(self.tcx)
)
} else {
format!(
"{item_kind} `{item_ident}` not found for this {}",
rcvr_ty.prefix_string(self.tcx)
)
};
err.span_label(span, label);
continue;
}
let pre = if is_ty_span {
ty_span.take();
format!(
"{item_kind} `{item_ident}` not found for this {} because it ",
Expand Down Expand Up @@ -1248,6 +1344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_ident,
item_kind,
bound_spans,
unsatisfied_predicates,
);

self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
Expand Down Expand Up @@ -1507,6 +1604,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_spans: &mut SortedMap<Span, Vec<String>>,
) {
let tcx = self.tcx;
let rcvr_ty_str = self.tcx.short_string(rcvr_ty, err.long_ty_path());
let mut type_params = FxIndexMap::default();

// Pick out the list of unimplemented traits on the receiver.
Expand Down Expand Up @@ -1798,14 +1896,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
spanned_predicates.sort_by_key(|(span, _)| *span);
for (_, (primary_spans, span_labels, predicates)) in spanned_predicates {
let mut tracker = TraitBoundDuplicateTracker::new();
let mut all_trait_bounds_for_rcvr = true;
for pred in &predicates {
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
let self_ty = pred.trait_ref.self_ty();
if self_ty.peel_refs() != rcvr_ty {
all_trait_bounds_for_rcvr = false;
break;
}
let is_ref = matches!(self_ty.kind(), ty::Ref(..));
tracker.track(pred.trait_ref.def_id, is_ref);
}
_ => {
all_trait_bounds_for_rcvr = false;
break;
}
}
}
let has_ref_dupes = tracker.has_ref_dupes();
let trait_def_ids = tracker.into_trait_def_ids();
let mut preds: Vec<_> = predicates
.iter()
.filter_map(|pred| format_pred(**pred))
.map(|(p, _)| format!("`{p}`"))
.collect();
preds.sort();
preds.dedup();
let msg = if let [pred] = &preds[..] {
let availability_note = if all_trait_bounds_for_rcvr
&& has_ref_dupes
&& trait_def_ids.len() > 1
&& matches!(rcvr_ty.kind(), ty::Adt(..))
{
let mut trait_names = trait_def_ids
.into_iter()
.map(|def_id| format!("`{}`", tcx.def_path_str(def_id)))
.collect::<Vec<_>>();
trait_names.sort();
listify(&trait_names, |name| name.to_string()).map(|traits| {
format!(
"for `{item_ident}` to be available, `{rcvr_ty_str}` must implement {traits}"
)
})
} else {
None
};
let msg = if let Some(availability_note) = availability_note {
availability_note
} else if let [pred] = &preds[..] {
format!("trait bound {pred} was not satisfied")
} else {
format!("the following trait bounds were not satisfied:\n{}", preds.join("\n"),)
Expand Down
88 changes: 45 additions & 43 deletions compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::parse::ParseStream;
use syn::spanned::Spanned;
use syn::{Attribute, Meta, Path, Token, Type, parse_quote};
use synstructure::{BindingInfo, Structure, VariantInfo};
Expand All @@ -11,7 +12,7 @@ use crate::diagnostics::error::{
DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err,
};
use crate::diagnostics::utils::{
FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
should_generate_arg, type_is_bool, type_is_unit, type_matches_path,
};
Expand Down Expand Up @@ -42,19 +43,13 @@ pub(crate) struct DiagnosticDeriveVariantBuilder {

/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
/// has the actual diagnostic message.
pub slug: SpannedOption<Path>,
pub slug: Option<Path>,

/// Error codes are a optional part of the struct attribute - this is only set to detect
/// multiple specifications.
pub code: SpannedOption<()>,
}

impl HasFieldMap for DiagnosticDeriveVariantBuilder {
fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
self.field_map.get(field)
}
}

impl DiagnosticDeriveKind {
/// Call `f` for the struct or for each variant of the enum, returning a `TokenStream` with the
/// tokens from `f` wrapped in an `match` expression. Emits errors for use of derive on unions
Expand Down Expand Up @@ -111,7 +106,7 @@ impl DiagnosticDeriveKind {

impl DiagnosticDeriveVariantBuilder {
pub(crate) fn primary_message(&self) -> Option<&Path> {
match self.slug.value_ref() {
match self.slug.as_ref() {
None => {
span_err(self.span, "diagnostic slug not specified")
.help(
Expand Down Expand Up @@ -169,7 +164,7 @@ impl DiagnosticDeriveVariantBuilder {
&self,
attr: &Attribute,
) -> Result<Option<(SubdiagnosticKind, Path, bool)>, DiagnosticDeriveError> {
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, self)? else {
let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, &self.field_map)? else {
// Some attributes aren't errors - like documentation comments - but also aren't
// subdiagnostics.
return Ok(None);
Expand All @@ -191,7 +186,7 @@ impl DiagnosticDeriveVariantBuilder {
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
});

Ok(Some((subdiag.kind, slug, subdiag.no_span)))
Ok(Some((subdiag.kind, slug, false)))
}

/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
Expand All @@ -209,47 +204,54 @@ impl DiagnosticDeriveVariantBuilder {
let name = attr.path().segments.last().unwrap().ident.to_string();
let name = name.as_str();

let mut first = true;

if name == "diag" {
let mut tokens = TokenStream::new();
attr.parse_nested_meta(|nested| {
let path = &nested.path;
attr.parse_args_with(|input: ParseStream<'_>| {
let mut input = &*input;
let slug_recovery_point = input.fork();

if first && (nested.input.is_empty() || nested.input.peek(Token![,])) {
self.slug.set_once(path.clone(), path.span().unwrap());
first = false;
return Ok(());
let slug = input.parse::<Path>()?;
if input.is_empty() || input.peek(Token![,]) {
self.slug = Some(slug);
} else {
input = &slug_recovery_point;
}

first = false;

let Ok(nested) = nested.value() else {
span_err(
nested.input.span().unwrap(),
"diagnostic slug must be the first argument",
)
.emit();
return Ok(());
};

if path.is_ident("code") {
self.code.set_once((), path.span().unwrap());

let code = nested.parse::<syn::Expr>()?;
tokens.extend(quote! {
diag.code(#code);
});
} else {
span_err(path.span().unwrap(), "unknown argument")
.note("only the `code` parameter is valid after the slug")
while !input.is_empty() {
input.parse::<Token![,]>()?;
// Allow trailing comma
if input.is_empty() {
break;
}
let arg_name: Path = input.parse::<Path>()?;
if input.peek(Token![,]) {
span_err(
arg_name.span().unwrap(),
"diagnostic slug must be the first argument",
)
.emit();

// consume the buffer so we don't have syntax errors from syn
let _ = nested.parse::<TokenStream>();
continue;
}
let arg_name = arg_name.require_ident()?;
input.parse::<Token![=]>()?;
let arg_value = input.parse::<syn::Expr>()?;
match arg_name.to_string().as_str() {
"code" => {
self.code.set_once((), arg_name.span().unwrap());
tokens.extend(quote! {
diag.code(#arg_value);
});
}
_ => {
span_err(arg_name.span().unwrap(), "unknown argument")
.note("only the `code` parameter is valid after the slug")
.emit();
}
}
}
Ok(())
})?;

return Ok(tokens);
}

Expand Down
Loading
Loading