Skip to content
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

Improve migration lint #58

Draft
wants to merge 33 commits into
base: rfc2229-migration-capture-kind
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
23c0334
2229: Reduce the size of closures with `capture_disjoint_fields`
arora-aman Jun 28, 2021
32fa964
Edition 2021 for tests
arora-aman Jun 29, 2021
38dcae2
Apply suggestions from code review
nikomatsakis Jul 7, 2021
b0f98c6
test integer log10 values close to all powers of 10
tspiteri Jul 7, 2021
ed76c11
special case for integer log10
tspiteri Jul 7, 2021
6053544
Check FromIterator trait impl in prelude collision check.
m-ou-se Jul 6, 2021
f77dd5a
Add test for trait check in prelude collision lint.
m-ou-se Jul 6, 2021
10d6b34
Add generic types to prelude collision lint test.
m-ou-se Jul 7, 2021
99b5d2a
Fix typo in comment.
m-ou-se Jul 8, 2021
2083207
Update src/test/ui/rust-2021/future-prelude-collision-unneeded.rs
nikomatsakis Jul 8, 2021
8b87e85
Auto merge of #86930 - tspiteri:int_log10, r=kennytm
bors Jul 8, 2021
d05eafa
Move the `PartialEq` and `Eq` impls for arrays to a separate file
scottmcm May 30, 2021
2456495
Stop generating `alloca`s+`memcmp` for simple array equality
scottmcm May 30, 2021
b63b2f1
PR feedback
scottmcm May 30, 2021
1216353
Implement the raw_eq intrinsic in codegen_cranelift
scottmcm May 31, 2021
039a3ba
Add another codegen test, array_eq_zero
scottmcm May 31, 2021
3d2869c
PR Feedback: Don't put SSA-only types in `CValue`s
scottmcm May 31, 2021
6444f24
Use cranelift's `Type::int` instead of doing the match myself
scottmcm Jun 1, 2021
07fb5ee
Adjust the threshold to look at the ABI, not just the size
scottmcm Jun 3, 2021
d064494
Bless a UI test
scottmcm Jul 8, 2021
fdfe819
Auto merge of #86701 - sexxi-goose:optimization, r=nikomatsakis
bors Jul 9, 2021
b090cd1
Auto merge of #86869 - sexxi-goose:rfc2229-migration-capture-kind, r=…
bors Jul 9, 2021
95fb131
Auto merge of #86904 - m-ou-se:prelude-collision-check-trait, r=nikom…
bors Jul 9, 2021
ee86f96
Auto merge of #85828 - scottmcm:raw-eq, r=oli-obk
bors Jul 9, 2021
0b7ff96
Add note on why the variable is not fully captured
roxelo Jul 6, 2021
0e8e89d
Update error message
roxelo Jul 6, 2021
2900c1a
Add note pointing to where a closure and it's captured variables are …
roxelo Jul 7, 2021
36eb544
Add note clarifying why a closure no longer implements a trait
roxelo Jul 7, 2021
81b062a
Fix wording
roxelo Jul 7, 2021
59f634b
Update comments
roxelo Jul 7, 2021
ca44372
Handle multi diagnostics
roxelo Jul 8, 2021
8cbeaf7
Address comments
roxelo Jul 9, 2021
08c6167
Ensure deterministic ordering for diagnostics
roxelo Jul 9, 2021
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: 34 additions & 0 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,40 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
);
ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
};

raw_eq, <T>(v lhs_ref, v rhs_ref) {
fn type_by_size(size: Size) -> Option<Type> {
Type::int(size.bits().try_into().ok()?)
}

let size = fx.layout_of(T).layout.size;
let is_eq_value =
if size == Size::ZERO {
// No bytes means they're trivially equal
fx.bcx.ins().iconst(types::I8, 1)
} else if let Some(clty) = type_by_size(size) {
// Can't use `trusted` for these loads; they could be unaligned.
let mut flags = MemFlags::new();
flags.set_notrap();
let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
fx.bcx.ins().bint(types::I8, eq)
} else {
// Just call `memcmp` (like slices do in core) when the
// size is too large or it's not a power-of-two.
let ptr_ty = pointer_ty(fx.tcx);
let signed_bytes = i64::try_from(size.bytes()).unwrap();
let bytes_val = fx.bcx.ins().iconst(ptr_ty, signed_bytes);
let params = vec![AbiParam::new(ptr_ty); 3];
let returns = vec![AbiParam::new(types::I32)];
let args = &[lhs_ref, rhs_ref, bytes_val];
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
fx.bcx.ins().bint(types::I8, eq)
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
};
}

if let Some((_, dest)) = destination {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_codegen_cranelift/src/value_and_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,10 @@ impl<'tcx> CPlace<'tcx> {
ptr.store(fx, data, MemFlags::trusted());
ptr.load(fx, dst_ty, MemFlags::trusted())
}

// `CValue`s should never contain SSA-only types, so if you ended
// up here having seen an error like `B1 -> I8`, then before
// calling `write_cvalue` you need to add a `bint` instruction.
_ => unreachable!("write_cvalue_transmute: {:?} -> {:?}", src_ty, dst_ty),
};
//fx.bcx.set_val_label(data, cranelift_codegen::ir::ValueLabel::new(var.index()));
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ impl CodegenCx<'b, 'tcx> {
let t_i32 = self.type_i32();
let t_i64 = self.type_i64();
let t_i128 = self.type_i128();
let t_isize = self.type_isize();
let t_f32 = self.type_f32();
let t_f64 = self.type_f64();

Expand Down Expand Up @@ -712,6 +713,10 @@ impl CodegenCx<'b, 'tcx> {
ifn!("llvm.assume", fn(i1) -> void);
ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);

// This isn't an "LLVM intrinsic", but LLVM's optimization passes
// recognize it like one and we assume it exists in `core::slice::cmp`
ifn!("memcmp", fn(i8p, i8p, t_isize) -> t_i32);

// variadic intrinsics
ifn!("llvm.va_start", fn(i8p) -> void);
ifn!("llvm.va_end", fn(i8p) -> void);
Expand Down
38 changes: 38 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,44 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
}
}

sym::raw_eq => {
use abi::Abi::*;
let tp_ty = substs.type_at(0);
let layout = self.layout_of(tp_ty).layout;
let use_integer_compare = match layout.abi {
Scalar(_) | ScalarPair(_, _) => true,
Uninhabited | Vector { .. } => false,
Aggregate { .. } => {
// For rusty ABIs, small aggregates are actually passed
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
// so we re-use that same threshold here.
layout.size <= self.data_layout().pointer_size * 2
}
};

let a = args[0].immediate();
let b = args[1].immediate();
if layout.size.bytes() == 0 {
self.const_bool(true)
} else if use_integer_compare {
let integer_ty = self.type_ix(layout.size.bits());
let ptr_ty = self.type_ptr_to(integer_ty);
let a_ptr = self.bitcast(a, ptr_ty);
let a_val = self.load(a_ptr, layout.align.abi);
let b_ptr = self.bitcast(b, ptr_ty);
let b_val = self.load(b_ptr, layout.align.abi);
self.icmp(IntPredicate::IntEQ, a_val, b_val)
} else {
let i8p_ty = self.type_i8p();
let a_ptr = self.bitcast(a, i8p_ty);
let b_ptr = self.bitcast(b, i8p_ty);
let n = self.const_usize(layout.size.bytes());
let llfn = self.get_intrinsic("memcmp");
let cmp = self.call(llfn, &[a_ptr, b_ptr, n], None);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
}
}

_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_mir/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
throw_ub_format!("`assume` intrinsic called with `false`");
}
}
sym::raw_eq => {
let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
self.write_scalar(result, dest)?;
}
_ => return Ok(false),
}

Expand Down Expand Up @@ -559,4 +563,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

self.memory.copy(src, align, dst, align, size, nonoverlapping)
}

pub(crate) fn raw_eq_intrinsic(
&mut self,
lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::PointerTag>,
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
assert!(!layout.is_unsized());

let lhs = self.read_scalar(lhs)?.check_init()?;
let rhs = self.read_scalar(rhs)?.check_init()?;
let lhs_bytes = self.memory.read_bytes(lhs, layout.size)?;
let rhs_bytes = self.memory.read_bytes(rhs, layout.size)?;
Ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ symbols! {
FormatSpec,
Formatter,
From,
FromIterator,
Future,
FxHashMap,
FxHashSet,
Expand Down Expand Up @@ -933,6 +934,7 @@ symbols! {
quote,
range_inclusive_new,
raw_dylib,
raw_eq,
raw_identifiers,
raw_ref_op,
re_rebalance_coherence,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_typeck/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,13 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {

sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),

sym::raw_eq => {
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
let param_ty =
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
(1, vec![param_ty; 2], tcx.types.bool)
}

other => {
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
return;
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_typeck/src/check/method/prelude2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use hir::ItemKind;
use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::Underscore;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;

use crate::check::{
method::probe::{self, Pick},
Expand Down Expand Up @@ -206,6 +208,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
}

// For from_iter, check if the type actually implements FromIterator.
// If we know it does not, we don't need to warn.
if method_name.name == sym::from_iter {
if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
if !self
.infcx
.type_implements_trait(
trait_def_id,
self_ty,
InternalSubsts::empty(),
self.param_env,
)
.may_apply()
{
return;
}
}
}

// No need to lint if this is an inherent method called on a specific type, like `Vec::foo(...)`,
// since such methods take precedence over trait methods.
if matches!(pick.kind, probe::PickKind::InherentImplPick) {
Expand Down
Loading