Skip to content

Rollup of 8 pull requests #141961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
861ee47
ci: switch `x86_64-msvc-{1,2}` back to Windows Server 2025 images
jieyouxu Jun 1, 2025
a6a1c1b
Separately check equality of the scalar types and compound types in t…
Sol-Ell May 30, 2025
bb5de7d
Update books
rustbot Jun 2, 2025
e7e884b
cleaned up some tests
Kivooeo May 31, 2025
4e71f24
make `x check` to use stage0 by default
onur-ozkan Jun 3, 2025
8a65d9f
make library profile to use stage 1 on `x check`
onur-ozkan Jun 3, 2025
ecc7dde
handle stage0 on `Std::check`
onur-ozkan Jun 2, 2025
9505178
run `x check` on mingw-check-2
onur-ozkan Jun 3, 2025
59d993b
use better default stage for `check::Std` when stage isn't explicit
onur-ozkan Jun 3, 2025
00a88b9
Remove get_dbg_loc from DebugInfoBuilderMethods
bjorn3 Jun 3, 2025
2e8401a
Remove type_test from IntrinsicCallBuilderMethods
bjorn3 Jun 3, 2025
ee99fba
Deconstruct values in the THIR visitor
ArtemIsmagilov Jun 2, 2025
624e1cd
Deconstruct values in the THIR visitor
ArtemIsmagilov Jun 2, 2025
1943766
Rollup merge of #141724 - Sol-Ell:issue-141141-fix, r=nnethercote
matthiaskrgr Jun 3, 2025
4fa33eb
Rollup merge of #141833 - Kivooeo:test-reform1, r=jieyouxu
matthiaskrgr Jun 3, 2025
5d32b5c
Rollup merge of #141861 - jieyouxu:windows-server-2025-20250527, r=Ko…
matthiaskrgr Jun 3, 2025
72f60fb
Rollup merge of #141914 - onur-ozkan:follow-ups, r=Kobzol
matthiaskrgr Jun 3, 2025
e61cd14
Rollup merge of #141918 - ArtemIsmagilov:issue-141849, r=nnethercote
matthiaskrgr Jun 3, 2025
209be9a
Rollup merge of #141923 - rustbot:docs-update, r=ehuss
matthiaskrgr Jun 3, 2025
757d0e7
Rollup merge of #141931 - ArtemIsmagilov:issue-141849_2, r=nnethercote
matthiaskrgr Jun 3, 2025
3772a16
Rollup merge of #141956 - bjorn3:minor_cg_ssa_cleanup, r=oli-obk
matthiaskrgr Jun 3, 2025
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
33 changes: 33 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,39 @@ impl TyKind {
None
}
}

/// Returns `true` if this type is considered a scalar primitive (e.g.,
/// `i32`, `u8`, `bool`, etc).
///
/// This check is based on **symbol equality** and does **not** remove any
/// path prefixes or references. If a type alias or shadowing is present
/// (e.g., `type i32 = CustomType;`), this method will still return `true`
/// for `i32`, even though it may not refer to the primitive type.
pub fn maybe_scalar(&self) -> bool {
let Some(ty_sym) = self.is_simple_path() else {
// unit type
return self.is_unit();
};
matches!(
ty_sym,
sym::i8
| sym::i16
| sym::i32
| sym::i64
| sym::i128
| sym::u8
| sym::u16
| sym::u32
| sym::u64
| sym::u128
| sym::f16
| sym::f32
| sym::f64
| sym::f128
| sym::char
| sym::bool
)
}
}

/// A pattern type pattern.
Expand Down
215 changes: 158 additions & 57 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::{path_local, path_std};

/// Expands a `#[derive(PartialEq)]` attribute into an implementation for the
/// target item.
pub(crate) fn expand_deriving_partial_eq(
cx: &ExtCtxt<'_>,
span: Span,
Expand All @@ -16,62 +18,6 @@ pub(crate) fn expand_deriving_partial_eq(
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
let base = true;
let expr = cs_fold(
true, // use foldl
cx,
span,
substr,
|cx, fold| match fold {
CsFold::Single(field) => {
let [other_expr] = &field.other_selflike_exprs[..] else {
cx.dcx()
.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
};

// We received arguments of type `&T`. Convert them to type `T` by stripping
// any leading `&`. This isn't necessary for type checking, but
// it results in better error messages if something goes wrong.
//
// Note: for arguments that look like `&{ x }`, which occur with packed
// structs, this would cause expressions like `{ self.x } == { other.x }`,
// which isn't valid Rust syntax. This wouldn't break compilation because these
// AST nodes are constructed within the compiler. But it would mean that code
// printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid
// syntax, which would be suboptimal. So we wrap these in parens, giving
// `({ self.x }) == ({ other.x })`, which is valid syntax.
let convert = |expr: &P<Expr>| {
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) =
&expr.kind
{
if let ExprKind::Block(..) = &inner.kind {
// `&{ x }` form: remove the `&`, add parens.
cx.expr_paren(field.span, inner.clone())
} else {
// `&x` form: remove the `&`.
inner.clone()
}
} else {
expr.clone()
}
};
cx.expr_binary(
field.span,
BinOpKind::Eq,
convert(&field.self_expr),
convert(other_expr),
)
}
CsFold::Combine(span, expr1, expr2) => {
cx.expr_binary(span, BinOpKind::And, expr1, expr2)
}
CsFold::Fieldless => cx.expr_bool(span, base),
},
);
BlockOrExpr::new_expr(expr)
}

let structural_trait_def = TraitDef {
span,
path: path_std!(marker::StructuralPartialEq),
Expand All @@ -97,7 +43,9 @@ pub(crate) fn expand_deriving_partial_eq(
ret_ty: Path(path_local!(bool)),
attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))),
combine_substructure: combine_substructure(Box::new(|a, b, c| {
BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c))
})),
}];

let trait_def = TraitDef {
Expand All @@ -113,3 +61,156 @@ pub(crate) fn expand_deriving_partial_eq(
};
trait_def.expand(cx, mitem, item, push)
}

/// Generates the equality expression for a struct or enum variant when deriving
/// `PartialEq`.
///
/// This function generates an expression that checks if all fields of a struct
/// or enum variant are equal.
/// - Scalar fields are compared first for efficiency, followed by compound
/// fields.
/// - If there are no fields, returns `true` (fieldless types are always equal).
///
/// Whether a field is considered "scalar" is determined by comparing the symbol
/// of its type to a set of known scalar type symbols (e.g., `i32`, `u8`, etc).
/// This check is based on the type's symbol.
///
/// ### Example 1
/// ```
/// #[derive(PartialEq)]
/// struct i32;
///
/// // Here, `field_2` is of type `i32`, but since it's a user-defined type (not
/// // the primitive), it will not be treated as scalar. The function will still
/// // check equality of `field_2` first because the symbol matches `i32`.
/// #[derive(PartialEq)]
/// struct Struct {
/// field_1: &'static str,
/// field_2: i32,
/// }
/// ```
///
/// ### Example 2
/// ```
/// mod ty {
/// pub type i32 = i32;
/// }
///
/// // Here, `field_2` is of type `ty::i32`, which is a type alias for `i32`.
/// // However, the function will not reorder the fields because the symbol for
/// // `ty::i32` does not match the symbol for the primitive `i32`
/// // ("ty::i32" != "i32").
/// #[derive(PartialEq)]
/// struct Struct {
/// field_1: &'static str,
/// field_2: ty::i32,
/// }
/// ```
///
/// For enums, the discriminant is compared first, then the rest of the fields.
///
/// # Panics
///
/// If called on static or all-fieldless enums/structs, which should not occur
/// during derive expansion.
fn get_substructure_equality_expr(
cx: &ExtCtxt<'_>,
span: Span,
substructure: &Substructure<'_>,
) -> P<Expr> {
use SubstructureFields::*;

match substructure.fields {
EnumMatching(.., fields) | Struct(.., fields) => {
let combine = move |acc, field| {
let rhs = get_field_equality_expr(cx, field);
if let Some(lhs) = acc {
// Combine the previous comparison with the current field
// using logical AND.
return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs));
}
// Start the chain with the first field's comparison.
Some(rhs)
};

// First compare scalar fields, then compound fields, combining all
// with logical AND.
return fields
.iter()
.filter(|field| !field.maybe_scalar)
.fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine)
// If there are no fields, treat as always equal.
.unwrap_or_else(|| cx.expr_bool(span, true));
}
EnumDiscr(disc, match_expr) => {
let lhs = get_field_equality_expr(cx, disc);
let Some(match_expr) = match_expr else {
return lhs;
};
// Compare the discriminant first (cheaper), then the rest of the
// fields.
return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone());
}
StaticEnum(..) => cx.dcx().span_bug(
span,
"unexpected static enum encountered during `derive(PartialEq)` expansion",
),
StaticStruct(..) => cx.dcx().span_bug(
span,
"unexpected static struct encountered during `derive(PartialEq)` expansion",
),
AllFieldlessEnum(..) => cx.dcx().span_bug(
span,
"unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion",
),
}
}

/// Generates an equality comparison expression for a single struct or enum
/// field.
///
/// This function produces an AST expression that compares the `self` and
/// `other` values for a field using `==`. It removes any leading references
/// from both sides for readability. If the field is a block expression, it is
/// wrapped in parentheses to ensure valid syntax.
///
/// # Panics
///
/// Panics if there are not exactly two arguments to compare (should be `self`
/// and `other`).
fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> {
let [rhs] = &field.other_selflike_exprs[..] else {
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
};

cx.expr_binary(
field.span,
BinOpKind::Eq,
wrap_block_expr(cx, peel_refs(&field.self_expr)),
wrap_block_expr(cx, peel_refs(rhs)),
)
}

/// Removes all leading immutable references from an expression.
///
/// This is used to strip away any number of leading `&` from an expression
/// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable
/// references are preserved.
fn peel_refs(mut expr: &P<Expr>) -> P<Expr> {
while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind {
expr = &inner;
}
expr.clone()
}

/// Wraps a block expression in parentheses to ensure valid AST in macro
/// expansion output.
///
/// If the given expression is a block, it is wrapped in parentheses; otherwise,
/// it is returned unchanged.
fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P<Expr>) -> P<Expr> {
if matches!(&expr.kind, ExprKind::Block(..)) {
return cx.expr_paren(expr.span, expr);
}
expr
}
5 changes: 4 additions & 1 deletion compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ pub(crate) struct FieldInfo {
/// The expressions corresponding to references to this field in
/// the other selflike arguments.
pub other_selflike_exprs: Vec<P<Expr>>,
pub maybe_scalar: bool,
}

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -1220,7 +1221,8 @@ impl<'a> MethodDef<'a> {

let self_expr = discr_exprs.remove(0);
let other_selflike_exprs = discr_exprs;
let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
let discr_field =
FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true };

let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
.map(|(&ident, selflike_arg)| {
Expand Down Expand Up @@ -1533,6 +1535,7 @@ impl<'a> TraitDef<'a> {
name: struct_field.ident,
self_expr,
other_selflike_exprs,
maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(),
}
})
.collect()
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_codegen_gcc/src/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
fn clear_dbg_loc(&mut self) {
self.location = None;
}

fn get_dbg_loc(&self) -> Option<Self::DILocation> {
self.location
}
}

/// Generate the `debug_context` in an MIR Body.
Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
cond
}

fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
// Unsupported.
self.context.new_rvalue_from_int(self.int_type, 0)
}

fn type_checked_load(
&mut self,
_llvtable: Self::Value,
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1815,8 +1815,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
let dbg_loc = self.get_dbg_loc();

// Test whether the function pointer is associated with the type identifier.
let cond = self.type_test(llfn, typeid_metadata);
// Test whether the function pointer is associated with the type identifier using the
// llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces
// calls to this intrinsic with code to test type membership.
let typeid = self.get_metadata_value(typeid_metadata);
let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]);
let bb_pass = self.append_sibling_block("type_test.pass");
let bb_fail = self.append_sibling_block("type_test.fail");
self.cond_br(cond, bb_pass, bb_fail);
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
}
}

impl<'ll> Builder<'_, 'll, '_> {
pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
}
}

impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
Expand Down Expand Up @@ -209,10 +215,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
}
}

fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
}

fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
}
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,13 +636,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
}

fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value {
// Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
// optimization pass replaces calls to this intrinsic with code to test type membership.
let typeid = self.get_metadata_value(typeid);
self.call_intrinsic("llvm.type.test", &[pointer, typeid])
}

fn type_checked_load(
&mut self,
llvtable: &'ll Value,
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
);
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
fn clear_dbg_loc(&mut self);
fn get_dbg_loc(&self) -> Option<Self::DILocation>;
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
fn set_var_name(&mut self, value: Self::Value, name: &str);
}
2 changes: 0 additions & 2 deletions compiler/rustc_codegen_ssa/src/traits/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
fn abort(&mut self);
fn assume(&mut self, val: Self::Value);
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
/// Trait method used to test whether a given pointer is associated with a type identifier.
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value;
/// Trait method used to load a function while testing if it is associated with a type
/// identifier.
fn type_checked_load(
Expand Down
Loading
Loading