Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bc4ab23
std: map ENOTSUP to ErrorKind::Unsupported
valentynkit Jun 29, 2026
11b6b76
Add regression test for ambiguous binop with as _
qaijuang May 15, 2026
5876162
Report binop ambiguity for unresolved as _ casts
qaijuang May 27, 2026
be32f36
update bpf abi to match LLVM 23
folkertdev Aug 13, 2026
c92b4fd
remove unused variable
panstromek Aug 15, 2026
df3231a
add comment explaining why we generate two match statements in Encoda…
panstromek Aug 15, 2026
71d2bed
add test to capture Encodable derive output
panstromek Aug 16, 2026
26ec2ac
Don't generate empty match for fieldless enums in Encodable derive
panstromek Aug 15, 2026
e5f1dea
remove redundant variable
panstromek Aug 15, 2026
3efc459
Avoid generating match for structs in Encodable derive
panstromek Aug 15, 2026
50804da
don't generate empty match for fieldless enums in Encodable derive
panstromek Aug 15, 2026
aa49d14
std: move ENOSYS next to the other Unsupported arms
valentynkit Aug 16, 2026
8107229
remove pointless span for partial-mitigations diagnostics
RalfJung Aug 16, 2026
2828d3e
mailmap: Add Wilfred
Wilfred Aug 17, 2026
93510b8
Don't generate code in for all Unit-like types Encodable derive
panstromek Aug 16, 2026
2a56199
document meaning of empty feature name in correct_fixed_length_vector…
RalfJung Aug 17, 2026
87fd659
Add regression test for missing size bound suggestion for trait item
lybang-lab Aug 17, 2026
9755e31
core/num: Implement feature `float_nan_to`
okaneco Aug 17, 2026
7b4d0c6
Rollup merge of #161137 - panstromek:cleanup-encode-macros, r=nnether…
jhpratt Aug 18, 2026
3225964
Rollup merge of #161193 - RalfJung:partial-mitigations, r=estebank
jhpratt Aug 18, 2026
5a1c5ce
Rollup merge of #161249 - KevinA-cpu:regression-test-85643, r=estebank
jhpratt Aug 18, 2026
23a5aec
Rollup merge of #156591 - qaijuang:diagnostics-as-infer-binop, r=chen…
jhpratt Aug 18, 2026
cdde1d2
Rollup merge of #158580 - valentynkit:enotsup-unsupported, r=workingj…
jhpratt Aug 18, 2026
c020bbb
Rollup merge of #161076 - folkertdev:bpf-structs, r=nagisa
jhpratt Aug 18, 2026
e16e85c
Rollup merge of #161240 - Wilfred:mailmap_wilfred, r=JonathanBrouwer
jhpratt Aug 18, 2026
5972c8b
Rollup merge of #161245 - RalfJung:target-feature-required-for-vector…
jhpratt Aug 18, 2026
4ef3577
Rollup merge of #161250 - okaneco:nan_to, r=clarfonthey
jhpratt Aug 18, 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
2 changes: 2 additions & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,8 @@ Weihang Lo <me@weihanglo.tw>
Weihang Lo <me@weihanglo.tw> <weihanglo@users.noreply.github.com>
Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com>
whitequark <whitequark@whitequark.org>
Wilfred Hughes <me@wilfred.me.uk>
Wilfred Hughes <me@wilfred.me.uk> <wilfred@meta.com>
Will Crichton <crichton.will@gmail.com> <wcrichto@stanford.edu>
Will Crichton <crichton.will@gmail.com> <wcrichto@cs.stanford.edu>
William Ting <io@williamting.com> <william.h.ting@gmail.com>
Expand Down
71 changes: 70 additions & 1 deletion compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::traits::ObligationCauseCode;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::AllowTwoPhase;
Expand All @@ -46,6 +47,7 @@ use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::{DUMMY_SP, Span, sym};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine};
use tracing::{debug, instrument};

use super::FnCtxt;
Expand Down Expand Up @@ -799,7 +801,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
let expr_span = self.expr_span_for_type_resolution(fcx);
self.expr_ty = fcx.structurally_resolve_type(expr_span, self.expr_ty);
self.cast_ty = fcx.structurally_resolve_type(self.cast_span, self.cast_ty);
self.cast_ty = fcx.resolve_vars_with_obligations(self.cast_ty);
if self.cast_ty.is_ty_var() {
self.cast_ty = if let Some(guar) = self.try_report_ambiguous_binop_for_infer_cast(fcx) {
let err = Ty::new_error(fcx.tcx, guar);
fcx.demand_suptype(self.cast_span, err, self.cast_ty);
err
} else {
fcx.type_must_be_known_at_this_point(self.cast_span, self.cast_ty)
};
}

debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);

Expand Down Expand Up @@ -839,6 +850,64 @@ impl<'a, 'tcx> CastCheck<'tcx> {
};
}
}

/// Prefer a pending operator ambiguity over a generic `as _` inference failure.
#[cold]
fn try_report_ambiguous_binop_for_infer_cast(
&self,
fcx: &FnCtxt<'a, 'tcx>,
) -> Option<ErrorGuaranteed> {
let errors: Vec<_> = fcx
.fulfillment_cx
.borrow()
.pending_obligations()
.into_iter()
.filter_map(|mut obligation| {
let predicate = fcx.resolve_vars_if_possible(obligation.predicate);
if !matches!(
predicate.kind().skip_binder(),
ty::PredicateKind::Clause(ty::ClauseKind::Trait(_))
) {
return None;
}
let cast_span = self.cast_span;

let ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. } =
obligation.cause.code()
else {
return None;
};
let lhs_ty = fcx.resolve_vars_if_possible(fcx.node_ty(*lhs_hir_id));
let rhs_ty = fcx.resolve_vars_if_possible(fcx.node_ty(*rhs_hir_id));

if (fcx.tcx.hir_span(*lhs_hir_id).contains(cast_span)
&& lhs_ty.contains(self.cast_ty))
|| (rhs_span.contains(cast_span) && rhs_ty.contains(self.cast_ty))
{
obligation.cause.span = cast_span;
obligation.predicate = predicate;

let ocx = ObligationCtxt::new_with_diagnostics(&fcx.infcx);
ocx.register_obligation(obligation);
ocx.evaluate_obligations_error_on_ambiguity().into_iter().find(|error| {
matches!(
error.code,
traits::FulfillmentErrorCode::Ambiguity { overflow: None }
)
})
} else {
None
}
})
.collect();

if errors.is_empty() {
None
} else {
Some(fcx.err_ctxt().report_fulfillment_errors(errors.into()))
}
}

/// Checks a cast, and report an error if one exists. In some cases, this
/// can return Ok and create type errors in the fcx rather than returning
/// directly. coercion-cast is handled in check instead of here.
Expand Down
95 changes: 52 additions & 43 deletions compiler/rustc_macros/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,31 +190,39 @@ fn encodable_body(

let encode_body = match s.variants() {
[] => {
quote! {
match *self {}
}
quote! {}
}
[_] => {
let encode_inner = s.each_variant(|vi| {
vi.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
let result = quote! {
::rustc_serialize::Encodable::<#encoder_ty>::encode(
#bind_ident,
__encoder,
);
};
result
})
.collect::<TokenStream>()
});
// Unit-like types don't need to encode anything.
// This covers fieldless structs and enums with zero or one fieldless variant.
[vi] if vi.bindings().is_empty() => {
quote! {}
}
[vi] => {
let pat = vi.pat();
let body = vi
.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
let result = quote! {
::rustc_serialize::Encodable::<#encoder_ty>::encode(
#bind_ident,
__encoder,
);
};
result
})
.collect::<TokenStream>();

quote! {
match *self { #encode_inner }
let #pat = *self;
#body
}
}
_ => {
// This code generates two separate match statements on purpose, because
// LLVM can optimize the first one into direct discriminant read.
// See: https://github.com/rust-lang/rust/pull/108440
let disc = {
let mut variant_idx = 0usize;
let encode_inner = s.each_variant(|_| {
Expand All @@ -241,29 +249,30 @@ fn encodable_body(
}
};

let mut variant_idx = 0usize;
let encode_inner = s.each_variant(|vi| {
let encode_fields: TokenStream = vi
.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
let result = quote! {
::rustc_serialize::Encodable::<#encoder_ty>::encode(
#bind_ident,
__encoder,
);
};
result
})
.collect();
variant_idx += 1;
encode_fields
});
quote! {
#disc
match *self {
#encode_inner
if s.variants().iter().all(|v| v.bindings().is_empty()) {
// Avoid generating second match statement if all variants are fieldless
disc
} else {
let encode_inner = s.each_variant(|vi| -> TokenStream {
vi.bindings()
.iter()
.map(|binding| {
let bind_ident = &binding.binding;
let result = quote! {
::rustc_serialize::Encodable::<#encoder_ty>::encode(
#bind_ident,
__encoder,
);
};
result
})
.collect()
});
quote! {
#disc
match *self {
#encode_inner
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ impl CStore {

pub fn report_session_incompatibilities(&self, tcx: TyCtxt<'_>, krate: &Crate) {
self.report_incompatible_target_modifiers(tcx);
self.report_incompatible_partial_mitigations(tcx, krate);
self.report_incompatible_partial_mitigations(tcx);
self.report_incompatible_async_drop_feature(tcx, krate);
}

Expand All @@ -473,7 +473,7 @@ impl CStore {
}
}

pub fn report_incompatible_partial_mitigations(&self, tcx: TyCtxt<'_>, krate: &Crate) {
pub fn report_incompatible_partial_mitigations(&self, tcx: TyCtxt<'_>) {
let my_mitigations = tcx.sess.gather_enabled_denied_partial_mitigations();
let mut my_mitigations: BTreeMap<_, _> =
my_mitigations.iter().map(|mitigation| (mitigation.kind, mitigation)).collect();
Expand All @@ -500,7 +500,6 @@ impl CStore {
*errors += 1;

tcx.dcx().emit_err(diagnostics::MitigationLessStrictInDependency {
span: krate.spans.inner_span.shrink_to_lo(),
mitigation_name: my_mitigation.kind.to_string(),
mitigation_level: my_mitigation.level.level_str().to_string(),
extern_crate: data.name(),
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_metadata/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,6 @@ pub(crate) struct UnusedCrateDependency {
"it is possible to disable `-Z allow-partial-mitigations={$mitigation_name}` via `-Z deny-partial-mitigations={$mitigation_name}`"
)]
pub(crate) struct MitigationLessStrictInDependency {
#[primary_span]
pub span: Span,
pub mitigation_name: String,
pub mitigation_level: String,
pub extern_crate: Symbol,
Expand Down
34 changes: 30 additions & 4 deletions compiler/rustc_target/src/callconv/bpf.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
// see https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/BPF/BPFCallingConv.td
use rustc_abi::TyAbiInterface;
use rustc_abi::{Reg, RegKind, Size, TyAbiInterface};

use crate::callconv::{ArgAbi, FnAbi};
use crate::callconv::{ArgAbi, CastTarget, FnAbi, Uniform};

fn classify_aggregate_type<Ty>(arg: &mut ArgAbi<'_, Ty>) {
let size = arg.layout.size;

match size.bits() {
0 => return,
1..=64 => {
arg.cast_to(Reg { kind: RegKind::Integer, size });
}
65..=128 => {
arg.cast_to(CastTarget::from(Uniform::new(Reg::i64(), Size::from_bytes(16))));
}
_ => {
arg.make_indirect();
}
}
}

fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
if !ret.layout.is_sized() {
// Not touching this...
return;
}

if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 {
ret.make_indirect();
classify_aggregate_type(ret);
} else {
ret.extend_integer_width_to(32);
}
Expand All @@ -15,12 +37,16 @@ fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
Ty: TyAbiInterface<'a, C> + Copy,
{
if !arg.layout.is_sized() {
// Not touching this...
return;
}
if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
arg.make_indirect();
return;
}
if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 {
arg.make_indirect();
classify_aggregate_type(arg);
} else {
arg.extend_integer_width_to(32);
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_target/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,8 @@ pub fn feature_to_arch_names(feature: &str) -> Vec<&'static str> {
}

// These arrays represent the least-constraining feature that is required for vector types up to a
// certain size to have their "proper" ABI on each architecture.
// certain size to have their "proper" ABI on each architecture. An empty feature name means
// that the given length is unconditionally available.
// Note that they must be kept sorted by vector size.
const X86_FEATURES_FOR_CORRECT_FIXED_LENGTH_VECTOR_ABI: &'static [(u64, &'static str)] =
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; // FIXME: might need changes for AVX10.
Expand Down
27 changes: 27 additions & 0 deletions library/core/src/num/f128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,33 @@ impl f128 {
pub const fn algebraic_rem(self, rhs: f128) -> f128 {
intrinsics::frem_algebraic(self, rhs)
}

/// Returns `self` if the value is not NaN, otherwise returns `replacement`
/// if `self` is NaN.
///
/// # Examples
///
/// ```
/// #![feature(f128)]
/// #![feature(float_nan_to)]
/// # #[cfg(target_has_reliable_f128)] {
///
/// let n = f128::NAN;
/// let x = 2.0f128;
/// let y = f128::INFINITY;
///
/// assert_eq!(n.nan_to(0.0f128), 0.0f128);
/// assert_eq!(x.nan_to(0.0f128), 2.0f128);
/// assert_eq!(y.nan_to(0.0f128), f128::INFINITY);
/// # }
/// ```
#[must_use = "method returns a new float and does not mutate the original value"]
#[unstable(feature = "float_nan_to", issue = "161248")]
#[rustc_const_unstable(feature = "float_nan_to", issue = "161248")]
#[inline]
pub const fn nan_to(self, replacement: f128) -> f128 {
if self.is_nan() { replacement } else { self }
}
}

// Functions in this module fall into `core_float_math`
Expand Down
27 changes: 27 additions & 0 deletions library/core/src/num/f16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,33 @@ impl f16 {
pub const fn algebraic_rem(self, rhs: f16) -> f16 {
intrinsics::frem_algebraic(self, rhs)
}

/// Returns `self` if the value is not NaN, otherwise returns `replacement`
/// if `self` is NaN.
///
/// # Examples
///
/// ```
/// #![feature(f16)]
/// #![feature(float_nan_to)]
/// # #[cfg(target_has_reliable_f16)] {
///
/// let n = f16::NAN;
/// let x = 2.0f16;
/// let y = f16::INFINITY;
///
/// assert_eq!(n.nan_to(0.0f16), 0.0f16);
/// assert_eq!(x.nan_to(0.0f16), 2.0f16);
/// assert_eq!(y.nan_to(0.0f16), f16::INFINITY);
/// # }
/// ```
#[must_use = "method returns a new float and does not mutate the original value"]
#[unstable(feature = "float_nan_to", issue = "161248")]
#[rustc_const_unstable(feature = "float_nan_to", issue = "161248")]
#[inline]
pub const fn nan_to(self, replacement: f16) -> f16 {
if self.is_nan() { replacement } else { self }
}
}

// Functions in this module fall into `core_float_math`
Expand Down
Loading
Loading