Skip to content
Draft
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
23 changes: 23 additions & 0 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,29 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::ty_and_layout_field(self, cx, i)
}

pub fn is_gapless<C>(self, cx: &C) -> bool
where
Ty: TyAbiInterface<'a, C> + Copy,
{
let Variants::Single { .. } = self.variants else {
return false;
};

let mut expected_offset = Size::ZERO;
for i in self.fields.index_by_increasing_offset() {
if self.fields.offset(i) != expected_offset {
return false;
}
expected_offset = self.fields.offset(i) + TyAndLayout::field(self, cx, i).size;
}

if expected_offset != self.size {
return false;
}

true
}

pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
where
Ty: TyAbiInterface<'a, C>,
Expand Down
71 changes: 54 additions & 17 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety};
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, MetaItem, Mutability, Safety};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Span, sym};
use rustc_span::{Ident, Span, kw, sym};
use thin_vec::thin_vec;

use crate::deriving::generic::ty::*;
Expand Down Expand Up @@ -125,7 +125,7 @@ fn get_substructure_equality_expr(
) -> Box<Expr> {
use SubstructureFields::*;

match substructure.fields {
let field_comparison = match substructure.fields {
EnumMatching(.., fields) | Struct(.., fields) => {
let combine = move |acc, field| {
let rhs = get_field_equality_expr(cx, field);
Expand All @@ -138,23 +138,35 @@ fn get_substructure_equality_expr(
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));
// If there are no fields, return true immediately.
// If there is just one, compare it.
// Otherwise, try to do a bitwise comparison.
match &fields[..] {
[] => return cx.expr_bool(span, true),
[field] => return get_field_equality_expr(cx, field),
_ => {
// First compare scalar fields, then compound fields, combining all
// with logical AND.
fields
.iter()
.filter(|field| !field.maybe_scalar)
.fold(
fields.iter().filter(|field| field.maybe_scalar).fold(None, combine),
combine,
)
.unwrap()
}
}
}
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());
if let Some(match_expr) = match_expr {
// Compare the discriminant first (cheaper), then the rest of the
// fields.
cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone())
} else {
lhs
}
}
StaticEnum(..) => cx.dcx().span_bug(
span,
Expand All @@ -168,6 +180,31 @@ fn get_substructure_equality_expr(
span,
"unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion",
),
};

if matches!(substructure.fields, Struct(..)) {
// Construct intrinsics::can_compare_bitwise<Self>()
let self_ty = cx.ty_path(cx.path_ident(span, Ident::with_dummy_span(kw::SelfUpper)));
let path = cx.expr_path(cx.path_all(
span,
true,
cx.std_path(&[sym::intrinsics, sym::can_compare_bitwise]),
vec![GenericArg::Type(self_ty)],
));
let cond = cx.expr_call(span, path, thin_vec![]);

let [_self, rhs] = &substructure.selflike_args[..] else {
cx.dcx().span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
};

// Construct intrinsics::compare_bitwise(self, other)
let compare_bitwise = cx.std_path(&[sym::intrinsics, sym::compare_bitwise]);
let call_compare_bitwise =
cx.expr_call_global(span, compare_bitwise, thin_vec![cx.expr_self(span), rhs.clone()]);

cx.expr_if(span, cond, call_compare_bitwise, Some(field_comparison))
} else {
field_comparison
}
}

Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ pub(crate) struct Substructure<'a> {
/// Verbatim access to any non-selflike arguments, i.e. arguments that
/// don't have type `&Self`.
pub nonselflike_args: &'a [Box<Expr>],
pub selflike_args: &'a [Box<Expr>],
pub fields: &'a SubstructureFields<'a>,
}

Expand Down Expand Up @@ -879,6 +880,7 @@ impl<'a> TraitDef<'a> {
self,
struct_def,
type_ident,
&selflike_args,
&nonselflike_args,
)
} else {
Expand Down Expand Up @@ -935,6 +937,7 @@ impl<'a> TraitDef<'a> {
self,
enum_def,
type_ident,
&selflike_args,
&nonselflike_args,
)
} else {
Expand Down Expand Up @@ -971,11 +974,12 @@ impl<'a> MethodDef<'a> {
cx: &ExtCtxt<'_>,
trait_: &TraitDef<'_>,
type_ident: Ident,
selflike_args: &[Box<Expr>],
nonselflike_args: &[Box<Expr>],
fields: &SubstructureFields<'_>,
) -> BlockOrExpr {
let span = trait_.span;
let substructure = Substructure { type_ident, nonselflike_args, fields };
let substructure = Substructure { type_ident, selflike_args, nonselflike_args, fields };
let mut f = self.combine_substructure.borrow_mut();
let f: &mut CombineSubstructureFunc<'_> = &mut *f;
f(cx, span, &substructure)
Expand Down Expand Up @@ -1150,6 +1154,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
selflike_args,
nonselflike_args,
&Struct(struct_def, selflike_fields),
)
Expand All @@ -1161,6 +1166,7 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
struct_def: &VariantData,
type_ident: Ident,
selflike_args: &[Box<Expr>],
nonselflike_args: &[Box<Expr>],
) -> BlockOrExpr {
let summary = trait_.summarise_struct(cx, struct_def);
Expand All @@ -1169,6 +1175,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
selflike_args,
nonselflike_args,
&StaticStruct(struct_def, summary),
)
Expand Down Expand Up @@ -1305,6 +1312,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args,
nonselflike_args,
&EnumDiscr(discr_field, None),
);
Expand All @@ -1316,6 +1324,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args,
nonselflike_args,
&AllFieldlessEnum(enum_def),
);
Expand All @@ -1329,6 +1338,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args,
nonselflike_args,
&EnumMatching(variant, Vec::new()),
);
Expand Down Expand Up @@ -1381,6 +1391,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args,
nonselflike_args,
&substructure,
)
Expand All @@ -1402,6 +1413,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args,
nonselflike_args,
&EnumMatching(v, Vec::new()),
)
Expand Down Expand Up @@ -1448,6 +1460,7 @@ impl<'a> MethodDef<'a> {
cx,
trait_,
type_ident,
&selflike_args.clone(),
nonselflike_args,
&EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
);
Expand All @@ -1464,12 +1477,14 @@ impl<'a> MethodDef<'a> {
trait_: &TraitDef<'_>,
enum_def: &EnumDef,
type_ident: Ident,
selflike_args: &[Box<Expr>],
nonselflike_args: &[Box<Expr>],
) -> BlockOrExpr {
self.call_substructure_method(
cx,
trait_,
type_ident,
selflike_args,
nonselflike_args,
&StaticEnum(enum_def),
)
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::breakpoint
| sym::bswap
| sym::caller_location
| sym::can_compare_bitwise
| sym::carrying_mul_add
| sym::ceilf16
| sym::ceilf32
| sym::ceilf64
| sym::ceilf128
| sym::cold_path
| sym::compare_bitwise
| sym::const_eval_select
| sym::contract_check_ensures
| sym::contract_check_requires
Expand Down Expand Up @@ -342,6 +344,18 @@ pub(crate) fn check_intrinsic_type(
vec![Ty::new_mut_ptr(tcx, param(0)), Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize],
tcx.types.unit,
),
sym::compare_bitwise => {
let br = ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon };
let first_arg =
Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BoundRegionKind::Anon };
let second_arg =
Ty::new_imm_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), param(0));

(1, 0, vec![first_arg, second_arg], tcx.types.bool)
}
sym::can_compare_bitwise => (1, 0, vec![], tcx.types.bool),
sym::compare_bytes => {
let byte_ptr = Ty::new_imm_ptr(tcx, tcx.types.u8);
(0, 0, vec![byte_ptr, byte_ptr, tcx.types.usize], tcx.types.i32)
Expand Down
32 changes: 31 additions & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ use hir::def::{CtorKind, DefKind};
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::LangItem;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::DefId;
use rustc_hir::{LangItem, find_attr};
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_type_ir::TyKind::*;
Expand Down Expand Up @@ -1987,6 +1988,35 @@ impl<'tcx> Ty<'tcx> {
}
}

pub fn is_bitwise_comparable(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Int(..) | ty::Uint(..) | ty::Bool | ty::Char => true,
ty::Array(element_ty, _len) => element_ty.is_bitwise_comparable(tcx),
ty::Adt(adt_def, args) => {
// Only structs
if !adt_def.is_struct() {
return false;
}
// All fields must be bitwise-comparable
if !adt_def.all_fields().all(|f| f.ty(tcx, args).is_bitwise_comparable(tcx)) {
return false;
}
// And the PartialEq impl for the ADT must be derived
let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP);
for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, self) {
if find_attr!(
tcx.get_all_attrs(def_id),
AttributeKind::AutomaticallyDerived(..)
) {
return true;
}
}
false
}
_ => false,
}
}

pub fn is_trivially_wf(self, tcx: TyCtxt<'tcx>) -> bool {
match *self.kind() {
ty::Bool
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_transform/src/known_panics_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}

// Don't try to evaluate the Operand::Const of calls to a concrete fn
if matches!(c.ty().kind(), ty::FnDef(..)) {
return None;
}

// Normalization needed b/c known panics lint runs in
// `mir_drops_elaborated_and_const_checked`, which happens before
// optimized MIR. Only after optimizing the MIR can we guarantee
Expand Down
Loading
Loading