Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-04-03 05:03:14 +00:00
commit 22382ebd5c
583 changed files with 12875 additions and 9896 deletions

View file

@ -2590,6 +2590,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "nu-ansi-term"
version = "0.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "num-conv"
version = "0.1.0"
@ -3560,6 +3569,7 @@ dependencies = [
name = "rustc_attr"
version = "0.0.0"
dependencies = [
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
@ -4773,6 +4783,8 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"askama",
"base64",
"byteorder",
"expect-test",
"indexmap",
"itertools 0.12.1",
@ -5358,9 +5370,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.30.7"
version = "0.30.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c385888ef380a852a16209afc8cfad22795dd8873d69c9a14d2e2088f118d18"
checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275"
dependencies = [
"cfg-if",
"core-foundation-sys",
@ -5778,17 +5790,6 @@ dependencies = [
"tracing-subscriber",
]
[[package]]
name = "tracing-log"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
@ -5807,7 +5808,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"matchers",
"nu-ansi-term",
"nu-ansi-term 0.46.0",
"once_cell",
"parking_lot",
"regex",
@ -5816,18 +5817,18 @@ dependencies = [
"thread_local",
"tracing",
"tracing-core",
"tracing-log 0.2.0",
"tracing-log",
]
[[package]]
name = "tracing-tree"
version = "0.2.5"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ec6adcab41b1391b08a308cc6302b79f8095d1673f6947c2dc65ffb028b0b2d"
checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675"
dependencies = [
"nu-ansi-term",
"nu-ansi-term 0.49.0",
"tracing-core",
"tracing-log 0.1.4",
"tracing-log",
"tracing-subscriber",
]

View file

@ -698,6 +698,7 @@ impl fmt::Display for AlignFromBytesError {
impl Align {
pub const ONE: Align = Align { pow2: 0 };
pub const EIGHT: Align = Align { pow2: 3 };
// LLVM has a maximal supported alignment of 2^29, we inherit that.
pub const MAX: Align = Align { pow2: 29 };
@ -707,19 +708,19 @@ impl Align {
}
#[inline]
pub fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
pub const fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
// Treat an alignment of 0 bytes like 1-byte alignment.
if align == 0 {
return Ok(Align::ONE);
}
#[cold]
fn not_power_of_2(align: u64) -> AlignFromBytesError {
const fn not_power_of_2(align: u64) -> AlignFromBytesError {
AlignFromBytesError::NotPowerOfTwo(align)
}
#[cold]
fn too_large(align: u64) -> AlignFromBytesError {
const fn too_large(align: u64) -> AlignFromBytesError {
AlignFromBytesError::TooLarge(align)
}

View file

@ -3341,7 +3341,7 @@ impl TryFrom<ItemKind> for ForeignItemKind {
pub type ForeignItem = Item<ForeignItemKind>;
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -1021,7 +1021,7 @@ where
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -768,7 +768,7 @@ impl DelimSpacing {
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }

View file

@ -1,5 +1,6 @@
//! Parsing and validation of builtin attributes
use rustc_abi::Align;
use rustc_ast::{self as ast, attr};
use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
use rustc_ast_pretty::pprust;
@ -919,10 +920,10 @@ pub enum ReprAttr {
ReprInt(IntType),
ReprRust,
ReprC,
ReprPacked(u32),
ReprPacked(Align),
ReprSimd,
ReprTransparent,
ReprAlign(u32),
ReprAlign(Align),
}
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
@ -968,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
let hint = match item.name_or_empty() {
sym::Rust => Some(ReprRust),
sym::C => Some(ReprC),
sym::packed => Some(ReprPacked(1)),
sym::packed => Some(ReprPacked(Align::ONE)),
sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent),
sym::align => {
@ -1209,11 +1210,17 @@ fn allow_unstable<'a>(
})
}
pub fn parse_alignment(node: &ast::LitKind) -> Result<u32, &'static str> {
pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
// `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first
if literal.get().is_power_of_two() {
// rustc_middle::ty::layout::Align restricts align to <= 2^29
if *literal <= 1 << 29 { Ok(literal.get() as u32) } else { Err("larger than 2^29") }
// Only possible error is larger than 2^29
literal
.get()
.try_into()
.ok()
.and_then(|v| Align::from_bytes(v).ok())
.ok_or("larger than 2^29")
} else {
Err("not a power of two")
}

View file

@ -540,19 +540,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
/// Suggest `map[k] = v` => `map.insert(k, v)` and the like.
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diag<'tcx>, span: Span) {
let Some(adt) = ty.ty_adt_def() else { return };
let did = adt.did();
if self.infcx.tcx.is_diagnostic_item(sym::HashMap, did)
|| self.infcx.tcx.is_diagnostic_item(sym::BTreeMap, did)
{
struct V<'a, 'tcx> {
/// Walks through the HIR, looking for the corresponding span for this error.
/// When it finds it, see if it corresponds to assignment operator whose LHS
/// is an index expr.
struct SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
assign_span: Span,
err: &'a mut Diag<'tcx>,
ty: Ty<'tcx>,
suggested: bool,
}
impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for SuggestIndexOperatorAlternativeVisitor<'a, 'tcx> {
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
hir::intravisit::walk_stmt(self, stmt);
let expr = match stmt.kind {
@ -645,7 +649,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) else { return };
let body = self.infcx.tcx.hir().body(body_id);
let mut v = V { assign_span: span, err, ty, suggested: false };
let mut v = SuggestIndexOperatorAlternativeVisitor {
assign_span: span,
err,
ty,
suggested: false,
};
v.visit_body(body);
if !v.suggested {
err.help(format!(

View file

@ -2279,7 +2279,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
CastKind::PointerFromExposedAddress => {
CastKind::PointerWithExposedProvenance => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(*ty);
@ -2289,7 +2289,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
span_mirbug!(
self,
rvalue,
"Invalid PointerFromExposedAddress cast {:?} -> {:?}",
"Invalid PointerWithExposedProvenance cast {:?} -> {:?}",
ty_from,
ty
)

View file

@ -114,6 +114,8 @@ builtin_macros_env_not_defined = environment variable `{$var}` not defined at co
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
.custom = use `std::env::var({$var_expr})` to read the variable at run time
builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Unicode string
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern

View file

@ -11,18 +11,19 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use std::env;
use std::env::VarError;
use thin_vec::thin_vec;
use crate::errors;
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option<Symbol> {
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
let var = var.as_str();
if let Some(value) = cx.sess.opts.logical_env.get(var) {
return Some(Symbol::intern(value));
return Ok(Symbol::intern(value));
}
// If the environment variable was not defined with the `--env-set` option, we try to retrieve it
// from rustc's environment.
env::var(var).ok().as_deref().map(Symbol::intern)
Ok(Symbol::intern(&env::var(var)?))
}
pub fn expand_option_env<'cx>(
@ -39,7 +40,7 @@ pub fn expand_option_env<'cx>(
};
let sp = cx.with_def_site_ctxt(sp);
let value = lookup_env(cx, var);
let value = lookup_env(cx, var).ok();
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
let e = match value {
None => {
@ -108,9 +109,9 @@ pub fn expand_env<'cx>(
let span = cx.with_def_site_ctxt(sp);
let value = lookup_env(cx, var);
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
let e = match value {
None => {
Err(err) => {
let ExprKind::Lit(token::Lit {
kind: LitKind::Str | LitKind::StrRaw(..), symbol, ..
}) = &var_expr.kind
@ -118,25 +119,33 @@ pub fn expand_env<'cx>(
unreachable!("`expr_to_string` ensures this is a string lit")
};
let guar = if let Some(msg_from_user) = custom_msg {
cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
} else if is_cargo_env_var(var.as_str()) {
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
span,
var: *symbol,
var_expr: var_expr.ast_deref(),
})
} else {
cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
span,
var: *symbol,
var_expr: var_expr.ast_deref(),
})
let guar = match err {
VarError::NotPresent => {
if let Some(msg_from_user) = custom_msg {
cx.dcx()
.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
} else if is_cargo_env_var(var.as_str()) {
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
span,
var: *symbol,
var_expr: var_expr.ast_deref(),
})
} else {
cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
span,
var: *symbol,
var_expr: var_expr.ast_deref(),
})
}
}
VarError::NotUnicode(_) => {
cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol })
}
};
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
Some(value) => cx.expr_str(span, value),
Ok(value) => cx.expr_str(span, value),
};
ExpandResult::Ready(MacEager::expr(e))
}

View file

@ -458,6 +458,14 @@ pub(crate) enum EnvNotDefined<'a> {
},
}
#[derive(Diagnostic)]
#[diag(builtin_macros_env_not_unicode)]
pub(crate) struct EnvNotUnicode {
#[primary_span]
pub(crate) span: Span,
pub(crate) var: Symbol,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_format_requires_string)]
pub(crate) struct FormatRequiresString {

View file

@ -650,7 +650,7 @@ fn codegen_stmt<'tcx>(
| CastKind::FnPtrToPtr
| CastKind::PtrToPtr
| CastKind::PointerExposeAddress
| CastKind::PointerFromExposedAddress,
| CastKind::PointerWithExposedProvenance,
ref operand,
to_ty,
) => {

View file

@ -68,7 +68,7 @@ pub(crate) fn maybe_codegen<'tcx>(
Some(CValue::by_val(ret_val, lhs.layout()))
}
}
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
}
}
@ -134,6 +134,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
BinOp::Div | BinOp::Rem => unreachable!(),
BinOp::Cmp => unreachable!(),
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
}

View file

@ -965,7 +965,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
});
}
sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
sym::simd_expose_addr | sym::simd_with_exposed_provenance | sym::simd_cast_ptr => {
intrinsic_args!(fx, args => (arg); intrinsic);
ret.write_cvalue_transmute(fx, arg);
}

View file

@ -40,6 +40,22 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
})
}
fn codegen_three_way_compare<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
signed: bool,
lhs: Value,
rhs: Value,
) -> CValue<'tcx> {
// This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
// <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
let val = fx.bcx.ins().isub(gt, lt);
CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span))))
}
fn codegen_compare_bin_op<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
bin_op: BinOp,
@ -47,6 +63,10 @@ fn codegen_compare_bin_op<'tcx>(
lhs: Value,
rhs: Value,
) -> CValue<'tcx> {
if bin_op == BinOp::Cmp {
return codegen_three_way_compare(fx, signed, lhs, rhs);
}
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
@ -59,7 +79,7 @@ pub(crate) fn codegen_binop<'tcx>(
in_rhs: CValue<'tcx>,
) -> CValue<'tcx> {
match bin_op {
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
match in_lhs.layout().ty.kind() {
ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
let signed = type_sign(in_lhs.layout().ty);
@ -160,7 +180,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
}
BinOp::Offset => unreachable!("Offset is not an integer operation"),
// Compare binops handles by `codegen_binop`.
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge => {
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
}
};

View file

@ -94,6 +94,10 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
self.const_int(self.type_i32(), i as i64)
}
fn const_i8(&self, i: i8) -> RValue<'gcc> {
self.const_int(self.type_i8(), i as i64)
}
fn const_u32(&self, i: u32) -> RValue<'gcc> {
self.const_uint(self.type_u32(), i as u64)
}

View file

@ -417,7 +417,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry"));
}
if let Some(align) = codegen_fn_attrs.alignment {
llvm::set_alignment(llfn, align as usize);
llvm::set_alignment(llfn, align);
}
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));

View file

@ -160,6 +160,10 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
self.const_int(self.type_i32(), i as i64)
}
fn const_i8(&self, i: i8) -> &'ll Value {
self.const_int(self.type_i8(), i as i64)
}
fn const_u32(&self, i: u32) -> &'ll Value {
self.const_uint(self.type_i32(), i as u64)
}

View file

@ -16,6 +16,7 @@ use rustc_middle::bug;
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Instance;
use rustc_target::abi::Align;
use std::cell::RefCell;
@ -23,7 +24,7 @@ pub(crate) mod ffi;
pub(crate) mod map_data;
pub mod mapgen;
const VAR_ALIGN_BYTES: usize = 8;
const VAR_ALIGN: Align = Align::EIGHT;
/// A context object for maintaining all state needed by the coverageinfo module.
pub struct CrateCoverageContext<'ll, 'tcx> {
@ -225,7 +226,7 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
llvm::set_global_constant(llglobal, true);
llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::set_section(llglobal, &covmap_section_name);
llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
llvm::set_alignment(llglobal, VAR_ALIGN);
cx.add_used_global(llglobal);
}
@ -255,7 +256,7 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
llvm::set_section(llglobal, covfun_section_name);
llvm::set_alignment(llglobal, VAR_ALIGN_BYTES);
llvm::set_alignment(llglobal, VAR_ALIGN);
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
cx.add_used_global(llglobal);
}

View file

@ -2139,7 +2139,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
}
if name == sym::simd_from_exposed_addr {
if name == sym::simd_with_exposed_provenance {
let (out_len, out_elem) = require_simd!(ret_ty, SimdReturn);
require!(
in_len == out_len,

View file

@ -11,6 +11,7 @@ pub use self::RealPredicate::*;
use libc::c_uint;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_llvm::RustString;
use rustc_target::abi::Align;
use std::cell::RefCell;
use std::ffi::{CStr, CString};
use std::str::FromStr;
@ -229,9 +230,9 @@ pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
}
}
pub fn set_alignment(llglobal: &Value, bytes: usize) {
pub fn set_alignment(llglobal: &Value, align: Align) {
unsafe {
ffi::LLVMSetAlignment(llglobal, bytes as c_uint);
ffi::LLVMSetAlignment(llglobal, align.bytes() as c_uint);
}
}

View file

@ -5,7 +5,7 @@ use crate::back::write::{
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
};
use crate::common::{IntPredicate, RealPredicate, TypeKind};
use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
use crate::errors;
use crate::meth;
use crate::mir;
@ -33,7 +33,7 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::Symbol;
@ -300,14 +300,35 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
/// Returns `rhs` sufficiently masked, truncated, and/or extended so that
/// it can be used to shift `lhs`.
///
/// Shifts in MIR are all allowed to have mismatched LHS & RHS types.
/// The shift methods in `BuilderMethods`, however, are fully homogeneous
/// (both parameters and the return type are all the same type).
///
/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
/// For 32- and 64-bit types, this matches the semantics
/// of Java. (See related discussion on #1877 and #10183.)
///
/// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
/// calls or operation flags to preserve as much freedom to optimize as possible.
pub fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
lhs: Bx::Value,
rhs: Bx::Value,
mut rhs: Bx::Value,
is_unchecked: bool,
) -> Bx::Value {
// Shifts may have any size int on the rhs
let mut rhs_llty = bx.cx().val_ty(rhs);
let mut lhs_llty = bx.cx().val_ty(lhs);
let mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, false);
if !is_unchecked {
rhs = bx.and(rhs, mask);
}
if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
rhs_llty = bx.cx().element_type(rhs_llty)
}
@ -317,6 +338,12 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let rhs_sz = bx.cx().int_width(rhs_llty);
let lhs_sz = bx.cx().int_width(lhs_llty);
if lhs_sz < rhs_sz {
if is_unchecked && bx.sess().opts.optimize != OptLevel::No {
// FIXME: Use `trunc nuw` once that's available
let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask);
bx.assume(inrange);
}
bx.trunc(rhs, lhs_llty)
} else if lhs_sz > rhs_sz {
// We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the

View file

@ -3,10 +3,9 @@
use rustc_hir::LangItem;
use rustc_middle::mir;
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
use rustc_middle::ty::{self, layout::TyAndLayout, TyCtxt};
use rustc_span::Span;
use crate::base;
use crate::traits::*;
#[derive(Copy, Clone)]
@ -128,44 +127,6 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
}
// To avoid UB from LLVM, these two functions mask RHS with an
// appropriate mask unconditionally (i.e., the fallback behavior for
// all shifts). For 32- and 64-bit types, this matches the semantics
// of Java. (See related discussion on #1877 and #10183.)
pub fn build_masked_lshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
lhs: Bx::Value,
rhs: Bx::Value,
) -> Bx::Value {
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
bx.shl(lhs, rhs)
}
pub fn build_masked_rshift<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
lhs_t: Ty<'tcx>,
lhs: Bx::Value,
rhs: Bx::Value,
) -> Bx::Value {
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bx, rhs);
let is_signed = lhs_t.is_signed();
if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
}
fn shift_mask_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
rhs: Bx::Value,
) -> Bx::Value {
let rhs_llty = bx.val_ty(rhs);
let shift_val = shift_mask_val(bx, rhs_llty, rhs_llty, false);
bx.and(rhs, shift_val)
}
pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
llty: Bx::Type,

View file

@ -3,10 +3,11 @@ use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};
use crate::base;
use crate::common::{self, IntPredicate};
use crate::common::IntPredicate;
use crate::traits::*;
use crate::MemFlags;
use rustc_hir as hir;
use rustc_middle::mir;
use rustc_middle::mir::Operand;
use rustc_middle::ty::cast::{CastTy, IntTy};
@ -508,7 +509,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Since int2ptr can have arbitrary integer types as input (so we have to do
// sign extension and all that), it is currently best handled in the same code
// path as the other integer-to-X casts.
| mir::CastKind::PointerFromExposedAddress => {
| mir::CastKind::PointerWithExposedProvenance => {
assert!(bx.cx().is_backend_immediate(cast));
let ll_t_out = bx.cx().immediate_backend_type(cast);
if operand.layout.abi.is_uninhabited() {
@ -860,14 +861,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.inbounds_gep(llty, lhs, &[rhs])
}
}
mir::BinOp::Shl => common::build_masked_lshift(bx, lhs, rhs),
mir::BinOp::ShlUnchecked => {
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
mir::BinOp::Shl | mir::BinOp::ShlUnchecked => {
let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShlUnchecked);
bx.shl(lhs, rhs)
}
mir::BinOp::Shr => common::build_masked_rshift(bx, input_ty, lhs, rhs),
mir::BinOp::ShrUnchecked => {
let rhs = base::cast_shift_expr_rhs(bx, lhs, rhs);
mir::BinOp::Shr | mir::BinOp::ShrUnchecked => {
let rhs = base::build_shift_expr_rhs(bx, lhs, rhs, op == mir::BinOp::ShrUnchecked);
if is_signed { bx.ashr(lhs, rhs) } else { bx.lshr(lhs, rhs) }
}
mir::BinOp::Ne
@ -882,6 +881,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.icmp(base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs)
}
}
mir::BinOp::Cmp => {
use std::cmp::Ordering;
debug_assert!(!is_float);
let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
// FIXME: This actually generates tighter assembly, and is a classic trick
// <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>
// However, as of 2023-11 it optimizes worse in things like derived
// `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
// better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
// be worth trying it in optimized builds as well.
let is_gt = bx.icmp(pred(hir::BinOpKind::Gt), lhs, rhs);
let gtext = bx.zext(is_gt, bx.type_i8());
let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
let ltext = bx.zext(is_lt, bx.type_i8());
bx.unchecked_ssub(gtext, ltext)
} else {
// These operations are those expected by `tests/codegen/integer-cmp.rs`,
// from <https://github.com/rust-lang/rust/pull/63767>.
let is_lt = bx.icmp(pred(hir::BinOpKind::Lt), lhs, rhs);
let is_ne = bx.icmp(pred(hir::BinOpKind::Ne), lhs, rhs);
let ge = bx.select(
is_ne,
bx.cx().const_i8(Ordering::Greater as i8),
bx.cx().const_i8(Ordering::Equal as i8),
);
bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
}
}
}
}

View file

@ -19,6 +19,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
fn const_bool(&self, val: bool) -> Self::Value;
fn const_i16(&self, i: i16) -> Self::Value;
fn const_i32(&self, i: i32) -> Self::Value;
fn const_i8(&self, i: i8) -> Self::Value;
fn const_u32(&self, i: u32) -> Self::Value;
fn const_u64(&self, i: u64) -> Self::Value;
fn const_u128(&self, i: u128) -> Self::Value;

View file

@ -222,6 +222,7 @@ const_eval_mut_deref =
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
const_eval_nested_static_in_thread_local = #[thread_local] does not support implicit nested statics, please create explicit static items and refer to them instead
const_eval_non_const_fmt_macro_call =
cannot call non-const formatting macro in {const_eval_const_context}s

View file

@ -25,6 +25,13 @@ pub(crate) struct DanglingPtrInFinal {
pub kind: InternKind,
}
#[derive(Diagnostic)]
#[diag(const_eval_nested_static_in_thread_local)]
pub(crate) struct NestedStaticInThreadLocal {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(const_eval_mutable_ptr_in_final)]
pub(crate) struct MutablePtrInFinal {

View file

@ -40,9 +40,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_immediate(*res, dest)?;
}
CastKind::PointerFromExposedAddress => {
CastKind::PointerWithExposedProvenance => {
let src = self.read_immediate(src)?;
let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
let res = self.pointer_with_exposed_provenance_cast(&src, cast_layout)?;
self.write_immediate(*res, dest)?;
}
@ -242,7 +242,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
}
pub fn pointer_from_exposed_address_cast(
pub fn pointer_with_exposed_provenance_cast(
&self,
src: &ImmTy<'tcx, M::Provenance>,
cast_to: TyAndLayout<'tcx>,

View file

@ -18,6 +18,7 @@ use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::TyAndLayout;
@ -27,7 +28,7 @@ use rustc_span::sym;
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
use crate::const_eval;
use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal};
use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal, NestedStaticInThreadLocal};
pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
'mir,
@ -106,13 +107,21 @@ fn intern_as_new_static<'tcx>(
DefKind::Static { mutability: alloc.0.mutability, nested: true },
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
feed.codegen_fn_attrs(tcx.codegen_fn_attrs(static_id).clone());
if tcx.is_thread_local_static(static_id.into()) {
tcx.dcx().emit_err(NestedStaticInThreadLocal { span: tcx.def_span(static_id) });
}
// These do not inherit the codegen attrs of the parent static allocation, since
// it doesn't make sense for them to inherit their `#[no_mangle]` and `#[link_name = ..]`
// and the like.
feed.codegen_fn_attrs(CodegenFnAttrs::new());
feed.eval_static_initializer(Ok(alloc));
feed.generics_of(tcx.generics_of(static_id).clone());
feed.def_ident_span(tcx.def_ident_span(static_id));
feed.explicit_predicates_of(tcx.explicit_predicates_of(static_id));
feed.feed_hir()
feed.feed_hir();
}
/// How a constant value should be interned.

View file

@ -235,6 +235,13 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
Self::from_scalar(Scalar::from_bool(b), layout)
}
#[inline]
pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self {
let ty = tcx.ty_ordering_enum(None);
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
Self::from_scalar(Scalar::from_i8(c as i8), layout)
}
#[inline]
pub fn to_const_int(self) -> ConstInt {
assert!(self.layout.ty.is_integral());
@ -785,7 +792,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -61,6 +61,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> (ImmTy<'tcx, M::Provenance>, bool) {
let res = Ord::cmp(&lhs, &rhs);
return (ImmTy::from_ordering(res, *self.tcx), false);
}
fn binary_char_op(
&self,
bin_op: mir::BinOp,
@ -69,6 +74,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> (ImmTy<'tcx, M::Provenance>, bool) {
use rustc_middle::mir::BinOp::*;
if bin_op == Cmp {
return self.three_way_compare(l, r);
}
let res = match bin_op {
Eq => l == r,
Ne => l != r,
@ -231,6 +240,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let r = self.sign_extend(r, right_layout) as i128;
return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
}
if bin_op == Cmp {
let l = self.sign_extend(l, left_layout) as i128;
let r = self.sign_extend(r, right_layout) as i128;
return Ok(self.three_way_compare(l, r));
}
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
Div if r == 0 => throw_ub!(DivisionByZero),
Rem if r == 0 => throw_ub!(RemainderByZero),
@ -270,6 +284,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
if bin_op == Cmp {
return Ok(self.three_way_compare(l, r));
}
let val = match bin_op {
Eq => ImmTy::from_bool(l == r, *self.tcx),
Ne => ImmTy::from_bool(l != r, *self.tcx),

View file

@ -1058,7 +1058,7 @@ where
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -547,7 +547,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
self.check_op(ops::RawPtrToIntCast);
}
Rvalue::Cast(CastKind::PointerFromExposedAddress, _, _) => {
Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => {
// Since no pointer can ever get exposed (rejected above), this is easy to support.
}

View file

@ -986,6 +986,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
)
}
}
Cmp => {
for x in [a, b] {
check_kinds!(
x,
"Cannot three-way compare non-integer type {:?}",
ty::Char | ty::Uint(..) | ty::Int(..)
)
}
}
AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
| ShrUnchecked => {
for x in [a, b] {
@ -1067,7 +1076,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// FIXME(dyn-star): make sure nothing needs to be done here.
}
// FIXME: Add Checks for these
CastKind::PointerFromExposedAddress
CastKind::PointerWithExposedProvenance
| CastKind::PointerExposeAddress
| CastKind::PointerCoercion(_) => {}
CastKind::IntToInt | CastKind::IntToFloat => {

View file

@ -19,7 +19,7 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
match op {
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
Eq | Ne | Lt | Le | Gt | Ge => false,
Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
}
}
@ -30,7 +30,7 @@ pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
use rustc_middle::mir::BinOp::*;
match op {
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
}
}

View file

@ -684,26 +684,11 @@ where
impl_stable_traits_for_trivial_type!(::std::path::Path);
impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
where
K: ToStableHashKey<HCX> + Eq,
V: HashStable<HCX>,
R: BuildHasher,
{
#[inline]
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
let key = key.to_stable_hash_key(hcx);
key.hash_stable(hcx, hasher);
value.hash_stable(hcx, hasher);
});
}
}
// It is not safe to implement HashStable for HashSet or any other collection type
// It is not safe to implement HashStable for HashSet, HashMap or any other collection type
// with unstable but observable iteration order.
// See https://github.com/rust-lang/compiler-team/issues/533 for further information.
impl<V, HCX> !HashStable<HCX> for std::collections::HashSet<V> {}
impl<K, V, HCX> !HashStable<HCX> for std::collections::HashMap<K, V> {}
impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
where
@ -730,35 +715,6 @@ where
}
}
fn stable_hash_reduce<HCX, I, C, F>(
hcx: &mut HCX,
hasher: &mut StableHasher,
mut collection: C,
length: usize,
hash_function: F,
) where
C: Iterator<Item = I>,
F: Fn(&mut StableHasher, &mut HCX, I),
{
length.hash_stable(hcx, hasher);
match length {
1 => {
hash_function(hasher, hcx, collection.next().unwrap());
}
_ => {
let hash = collection
.map(|value| {
let mut hasher = StableHasher::new();
hash_function(&mut hasher, hcx, value);
hasher.finish::<Hash128>()
})
.reduce(|accum, value| accum.wrapping_add(value));
hash.hash_stable(hcx, hasher);
}
}
}
/// Controls what data we do or do not hash.
/// Whenever a `HashStable` implementation caches its
/// result, it needs to include `HashingControls` as part

View file

@ -102,9 +102,9 @@ pub type PResult<'a, T> = Result<T, PErr<'a>>;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]

View file

@ -48,6 +48,23 @@ impl<'a> ExtCtxt<'a> {
ast::Path { span, segments, tokens: None }
}
pub fn macro_call(
&self,
span: Span,
path: ast::Path,
delim: ast::token::Delimiter,
tokens: ast::tokenstream::TokenStream,
) -> P<ast::MacCall> {
P(ast::MacCall {
path,
args: P(ast::DelimArgs {
dspan: ast::tokenstream::DelimSpan { open: span, close: span },
delim,
tokens,
}),
})
}
pub fn ty_mt(&self, ty: P<ast::Ty>, mutbl: ast::Mutability) -> ast::MutTy {
ast::MutTy { ty, mutbl }
}
@ -265,6 +282,10 @@ impl<'a> ExtCtxt<'a> {
self.expr(span, ast::ExprKind::Field(expr, field))
}
pub fn expr_macro_call(&self, span: Span, call: P<ast::MacCall>) -> P<ast::Expr> {
self.expr(span, ast::ExprKind::MacCall(call))
}
pub fn expr_binary(
&self,
sp: Span,
@ -410,16 +431,19 @@ impl<'a> ExtCtxt<'a> {
self.expr(sp, ast::ExprKind::Tup(exprs))
}
pub fn expr_fail(&self, span: Span, msg: Symbol) -> P<ast::Expr> {
self.expr_call_global(
span,
[sym::std, sym::rt, sym::begin_panic].iter().map(|s| Ident::new(*s, span)).collect(),
thin_vec![self.expr_str(span, msg)],
)
}
pub fn expr_unreachable(&self, span: Span) -> P<ast::Expr> {
self.expr_fail(span, Symbol::intern("internal error: entered unreachable code"))
self.expr_macro_call(
span,
self.macro_call(
span,
self.path_global(
span,
[sym::std, sym::unreachable].map(|s| Ident::new(s, span)).to_vec(),
),
ast::token::Delimiter::Parenthesis,
ast::tokenstream::TokenStream::default(),
),
)
}
pub fn expr_ok(&self, sp: Span, expr: P<ast::Expr>) -> P<ast::Expr> {

View file

@ -266,7 +266,7 @@ struct MatcherPos {
}
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(MatcherPos, 16);
impl MatcherPos {

View file

@ -3762,7 +3762,7 @@ impl<'hir> Node<'hir> {
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
// tidy-alphabetical-start

View file

@ -226,6 +226,7 @@ language_item_table! {
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
OrderingEnum, sym::Ordering, ordering_enum, Target::Enum, GenericRequirement::Exact(0);
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;

View file

@ -54,14 +54,20 @@ impl<'tcx> Bounds<'tcx> {
span: Span,
polarity: ty::PredicatePolarity,
) {
self.clauses.push((
let clause = (
trait_ref
.map_bound(|trait_ref| {
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
})
.to_predicate(tcx),
span,
));
);
// FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
if tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
self.clauses.insert(0, clause);
} else {
self.clauses.push(clause);
}
}
pub fn push_projection_bound(

View file

@ -964,7 +964,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
for r in attr::parse_repr_attr(tcx.sess, attr) {
if let attr::ReprPacked(pack) = r
&& let Some(repr_pack) = repr.pack
&& pack as u64 != repr_pack.bytes()
&& pack != repr_pack
{
struct_span_code_err!(
tcx.dcx(),

View file

@ -107,6 +107,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
| sym::cttz
| sym::bswap
| sym::bitreverse
| sym::three_way_compare
| sym::discriminant_value
| sym::type_id
| sym::likely
@ -418,6 +419,10 @@ pub fn check_intrinsic_type(
| sym::bswap
| sym::bitreverse => (1, 0, vec![param(0)], param(0)),
sym::three_way_compare => {
(1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span)))
}
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
(1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool]))
}
@ -454,9 +459,8 @@ pub fn check_intrinsic_type(
sym::unchecked_div | sym::unchecked_rem | sym::exact_div => {
(1, 0, vec![param(0), param(0)], param(0))
}
sym::unchecked_shl | sym::unchecked_shr | sym::rotate_left | sym::rotate_right => {
(1, 0, vec![param(0), param(0)], param(0))
}
sym::unchecked_shl | sym::unchecked_shr => (2, 0, vec![param(0), param(1)], param(0)),
sym::rotate_left | sym::rotate_right => (1, 0, vec![param(0), param(0)], param(0)),
sym::unchecked_add | sym::unchecked_sub | sym::unchecked_mul => {
(1, 0, vec![param(0), param(0)], param(0))
}
@ -624,7 +628,7 @@ pub fn check_intrinsic_type(
| sym::simd_as
| sym::simd_cast_ptr
| sym::simd_expose_addr
| sym::simd_from_exposed_addr => (2, 0, vec![param(0)], param(1)),
| sym::simd_with_exposed_provenance => (2, 0, vec![param(0)], param(1)),
sym::simd_bitmask => (2, 0, vec![param(0)], param(1)),
sym::simd_select | sym::simd_select_bitmask => {
(2, 0, vec![param(0), param(1), param(1)], param(1))

View file

@ -418,8 +418,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
{
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
struct V;
impl<'v> Visitor<'v> for V {
/// Look for `_` anywhere in the signature of a `for<> ||` closure.
/// This is currently disallowed.
struct FindInferInClosureWithBinder;
impl<'v> Visitor<'v> for FindInferInClosureWithBinder {
type Result = ControlFlow<Span>;
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
if matches!(t.kind, hir::TyKind::Infer) {
@ -429,7 +431,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
}
V.visit_ty(ty).break_value()
FindInferInClosureWithBinder.visit_ty(ty).break_value()
}
let infer_in_rt_sp = match fn_decl.output {

View file

@ -1,6 +1,6 @@
use crate::errors::{
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
};
use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::HirTyLowerer;
@ -8,19 +8,26 @@ use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::MultiSpan;
use rustc_errors::{
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
use rustc_middle::query::Key;
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, suggest_constraining_type_param};
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{Binder, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::BytePos;
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
use rustc_trait_selection::traits::{
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@ -1024,6 +1031,170 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ok(())
}
}
pub fn report_prohibit_generics_error<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>,
) -> ErrorGuaranteed {
#[derive(PartialEq, Eq, Hash)]
enum ProhibitGenericsArg {
Lifetime,
Type,
Const,
Infer,
}
let mut prohibit_args = FxIndexSet::default();
args_visitors.for_each(|arg| {
match arg {
hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
};
});
let types_and_spans: Vec<_> = segments
.clone()
.flat_map(|segment| {
if segment.args().args.is_empty() {
None
} else {
Some((
match segment.res {
hir::def::Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name())
}
hir::def::Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) =>
{
format!("{} `{name}`", segment.res.descr())
}
hir::def::Res::Err => "this type".to_string(),
_ => segment.res.descr().to_string(),
},
segment.ident.span,
))
}
})
.collect();
let this_type = match &types_and_spans[..] {
[.., _, (last, _)] => format!(
"{} and {last}",
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
.intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
[] => "this type".to_string(),
};
let arg_spans: Vec<Span> = segments
.clone()
.flat_map(|segment| segment.args().args)
.map(|arg| arg.span())
.collect();
let mut kinds = Vec::with_capacity(4);
prohibit_args.iter().for_each(|arg| match arg {
ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
ProhibitGenericsArg::Type => kinds.push("type"),
ProhibitGenericsArg::Const => kinds.push("const"),
ProhibitGenericsArg::Infer => kinds.push("generic"),
});
let (kind, s) = match kinds[..] {
[.., _, last] => (
format!(
"{} and {last}",
kinds[..kinds.len() - 1]
.iter()
.map(|&x| x)
.intersperse(", ")
.collect::<String>()
),
"s",
),
[only] => (only.to_string(), ""),
[] => unreachable!("expected at least one generic to prohibit"),
};
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(
self.tcx().dcx(),
span,
E0109,
"{kind} arguments are not allowed on {this_type}",
);
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
for (what, span) in types_and_spans {
err.span_label(span, format!("not allowed on {what}"));
}
generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
}
pub fn report_trait_object_addition_traits_error(
&self,
regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1];
let mut err = struct_span_code_err!(
tcx.dcx(),
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
);
additional_trait.label_with_exp_info(
&mut err,
"additional non-auto trait",
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
err.help(format!(
"consider creating a new trait with all of these as supertraits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
));
err.note(
"auto-traits like `Send` and `Sync` are traits that have special properties; \
for more information on them, visit \
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
}
pub fn report_trait_object_with_no_traits_error(
&self,
span: Span,
trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let trait_alias_span = trait_bounds
.iter()
.map(|&(trait_ref, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
let reported =
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
self.set_tainted_by_errors(reported);
reported
}
}
/// Emits an error regarding forbidden type binding associations
@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
tcx: TyCtxt<'_>,
span: Span,
segment: Option<(&hir::PathSegment<'_>, Span)>,
) {
) -> ErrorGuaranteed {
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
span,
fn_trait_expansion: if let Some((segment, span)) = segment
@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
} else {
None
},
});
})
}
pub(crate) fn fn_trait_to_string(
@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
}
}
/// Used for generics args error extend.
pub enum GenericsArgsErrExtend<'tcx> {
EnumVariant {
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
adt_def: AdtDef<'tcx>,
},
OpaqueTy,
PrimTy(hir::PrimTy),
SelfTyAlias {
def_id: DefId,
span: Span,
},
SelfTyParam(Span),
TyParam(DefId),
DefVariant,
None,
}
fn generics_args_err_extend<'a>(
tcx: TyCtxt<'_>,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err: &mut Diag<'_>,
err_extend: GenericsArgsErrExtend<'_>,
) {
match err_extend {
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
err.note("enum variants can't have type parameters");
let type_name = tcx.item_name(adt_def.did());
let msg = format!(
"you might have meant to specify type parameters on enum \
`{type_name}`"
);
let Some(args) = assoc_segment.args else {
return;
};
// Get the span of the generics args *including* the leading `::`.
// We do so by stretching args.span_ext to the left by 2. Earlier
// it was done based on the end of assoc segment but that sometimes
// led to impossible spans and caused issues like #116473
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
if tcx.generics_of(adt_def.did()).count() == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
args_span,
format!("{type_name} doesn't have generic parameters"),
"",
Applicability::MachineApplicable,
);
return;
}
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
err.note(msg);
return;
};
let (qself_sugg_span, is_self) =
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments {
// `segment` is the previous to last element on the path,
// which would normally be the `enum` itself, while the last
// `_` `PathSegment` corresponds to the variant.
[
..,
hir::PathSegment {
ident, args, res: Res::Def(DefKind::Enum, _), ..
},
_,
] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
ident
.span
.shrink_to_hi()
.to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
false,
),
[segment] => {
(
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
segment.ident.span.shrink_to_hi().to(segment
.args
.map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
kw::SelfUpper == segment.ident.name,
)
}
_ => {
err.note(msg);
return;
}
}
} else {
err.note(msg);
return;
};
let suggestion = vec![
if is_self {
// Account for people writing `Self::Variant::<Args>`, where
// `Self` is the enum, and suggest replacing `Self` with the
// appropriate type: `Type::<Args>::Variant`.
(qself.span, format!("{type_name}{snippet}"))
} else {
(qself_sugg_span, snippet)
},
(args_span, String::new()),
];
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
}
GenericsArgsErrExtend::PrimTy(prim_ty) => {
let name = prim_ty.name_str();
for segment in segments {
if let Some(args) = segment.args {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
format!("primitive type `{name}` doesn't have generic parameters"),
"",
Applicability::MaybeIncorrect,
);
}
}
}
GenericsArgsErrExtend::OpaqueTy => {
err.note("`impl Trait` types can't have type parameters");
}
GenericsArgsErrExtend::DefVariant => {
err.note("enum variants can't have type parameters");
}
GenericsArgsErrExtend::TyParam(def_id) => {
if let Some(span) = tcx.def_ident_span(def_id) {
let name = tcx.item_name(def_id);
err.span_note(span, format!("type parameter `{name}` defined here"));
}
}
GenericsArgsErrExtend::SelfTyParam(span) => {
err.span_suggestion_verbose(
span,
"the `Self` type doesn't accept type parameters",
"",
Applicability::MaybeIncorrect,
);
}
GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
let span_of_impl = tcx.span_of_impl(def_id);
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did(),
_ => return,
};
let type_name = tcx.item_name(def_id);
let span_of_ty = tcx.def_ident_span(def_id);
let generics = tcx.generics_of(def_id).count();
let msg = format!("`Self` is of type `{ty}`");
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
let mut span: MultiSpan = vec![t_sp].into();
span.push_span_label(
i_sp,
format!("`Self` is on type `{type_name}` in this `impl`"),
);
let mut postfix = "";
if generics == 0 {
postfix = ", which doesn't have generic parameters";
}
span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
err.span_note(span, msg);
} else {
err.note(msg);
}
for segment in segments {
if let Some(args) = segment.args
&& segment.ident.name == kw::SelfUpper
{
if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MachineApplicable,
);
return;
} else {
err.span_suggestion_verbose(
segment.ident.span,
format!(
"the `Self` type doesn't accept type parameters, use the \
concrete type's name `{type_name}` instead if you want to \
specify its type parameters"
),
type_name,
Applicability::MaybeIncorrect,
);
}
}
}
}
_ => {}
}
}

View file

@ -14,7 +14,7 @@
//! trait references and bounds.
mod bounds;
mod errors;
pub mod errors;
pub mod generics;
mod lint;
mod object_safety;
@ -22,14 +22,14 @@ mod object_safety;
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::AmbiguousLifetimeBound;
use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@ -46,7 +46,7 @@ use rustc_middle::ty::{
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@ -632,7 +632,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_ref: &hir::TraitRef<'tcx>,
self_ty: Ty<'tcx>,
) -> ty::TraitRef<'tcx> {
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.lower_mono_trait_ref(
trait_ref.path.span,
@ -681,7 +684,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
let (generic_args, arg_count) = self.lower_generic_args_of_path(
@ -995,8 +1001,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_ref_id: hir::HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &hir::Ty<'_>,
assoc_segment: &hir::PathSegment<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
debug!(%qself_ty, ?assoc_segment.ident);
@ -1020,99 +1026,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
err.note("enum variants can't have type parameters");
let type_name = tcx.item_name(adt_def.did());
let msg = format!(
"you might have meant to specify type parameters on enum \
`{type_name}`"
);
let Some(args) = assoc_segment.args else {
return;
};
// Get the span of the generics args *including* the leading `::`.
// We do so by stretching args.span_ext to the left by 2. Earlier
// it was done based on the end of assoc segment but that sometimes
// led to impossible spans and caused issues like #116473
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
if tcx.generics_of(adt_def.did()).count() == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
args_span,
format!("{type_name} doesn't have generic parameters"),
"",
Applicability::MachineApplicable,
);
return;
}
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
else {
err.note(msg);
return;
};
let (qself_sugg_span, is_self) =
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
&qself.kind
{
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments {
// `segment` is the previous to last element on the path,
// which would normally be the `enum` itself, while the last
// `_` `PathSegment` corresponds to the variant.
[
..,
hir::PathSegment {
ident,
args,
res: Res::Def(DefKind::Enum, _),
..
},
_,
] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
ident.span.shrink_to_hi().to(args
.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
false,
),
[segment] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
segment.ident.span.shrink_to_hi().to(segment
.args
.map_or(segment.ident.span.shrink_to_hi(), |a| {
a.span_ext
})),
kw::SelfUpper == segment.ident.name,
),
_ => {
err.note(msg);
return;
}
}
} else {
err.note(msg);
return;
};
let suggestion = vec![
if is_self {
// Account for people writing `Self::Variant::<Args>`, where
// `Self` is the enum, and suggest replacing `Self` with the
// appropriate type: `Type::<Args>::Variant`.
(qself.span, format!("{type_name}{snippet}"))
} else {
(qself_sugg_span, snippet)
},
(args_span, String::new()),
];
err.multipart_suggestion_verbose(
msg,
suggestion,
Applicability::MaybeIncorrect,
);
});
let _ = self.prohibit_generic_args(
slice::from_ref(assoc_segment).iter(),
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
);
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
} else {
variant_resolution = Some(variant_def.def_id);
@ -1624,111 +1541,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn prohibit_generic_args<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
extend: impl Fn(&mut Diag<'_>),
) -> bool {
let args = segments.clone().flat_map(|segment| segment.args().args);
let (lt, ty, ct, inf) =
args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
hir::GenericArg::Type(_) => (lt, true, ct, inf),
hir::GenericArg::Const(_) => (lt, ty, true, inf),
hir::GenericArg::Infer(_) => (lt, ty, ct, true),
});
let mut emitted = false;
if lt || ty || ct || inf {
let types_and_spans: Vec<_> = segments
.clone()
.flat_map(|segment| {
if segment.args().args.is_empty() {
None
} else {
Some((
match segment.res {
Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name())
}
Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) =>
{
format!("{} `{name}`", segment.res.descr())
}
Res::Err => "this type".to_string(),
_ => segment.res.descr().to_string(),
},
segment.ident.span,
))
}
})
.collect();
let this_type = match &types_and_spans[..] {
[.., _, (last, _)] => format!(
"{} and {last}",
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
.intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
[] => "this type".to_string(),
};
let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
let mut kinds = Vec::with_capacity(4);
if lt {
kinds.push("lifetime");
}
if ty {
kinds.push("type");
}
if ct {
kinds.push("const");
}
if inf {
kinds.push("generic");
}
let (kind, s) = match kinds[..] {
[.., _, last] => (
format!(
"{} and {last}",
kinds[..kinds.len() - 1]
.iter()
.map(|&x| x)
.intersperse(", ")
.collect::<String>()
),
"s",
),
[only] => (only.to_string(), ""),
[] => unreachable!("expected at least one generic to prohibit"),
};
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(
self.tcx().dcx(),
span,
E0109,
"{kind} arguments are not allowed on {this_type}",
);
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
for (what, span) in types_and_spans {
err.span_label(span, format!("not allowed on {what}"));
}
extend(&mut err);
self.set_tainted_by_errors(err.emit());
emitted = true;
err_extend: GenericsArgsErrExtend<'_>,
) -> Result<(), ErrorGuaranteed> {
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
let mut result = Ok(());
if let Some(_) = args_visitors.clone().next() {
result = Err(self.report_prohibit_generics_error(
segments.clone(),
args_visitors,
err_extend,
));
}
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
prohibit_assoc_item_binding(self.tcx(), b.span, None);
return true;
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
}
}
emitted
result
}
/// Probe path segments that are semantically allowed to have generic arguments.
@ -1893,9 +1725,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Check for desugared `impl Trait`.
assert!(tcx.is_type_alias_impl_trait(did));
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generic_args(item_segment.1.iter(), |err| {
err.note("`impl Trait` types can't have type parameters");
});
let _ = self
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
Ty::new_opaque(tcx, did, args)
}
@ -1908,7 +1739,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
did,
) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.lower_path_segment(span, did, path.segments.last().unwrap())
}
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@ -1920,13 +1754,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
let indices: FxHashSet<_> =
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
self.prohibit_generic_args(
let _ = self.prohibit_generic_args(
path.segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) { Some(seg) } else { None }
}),
|err| {
err.note("enum variants can't have type parameters");
},
GenericsArgsErrExtend::DefVariant,
);
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
@ -1934,27 +1766,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::Def(DefKind::TyParam, def_id) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
if let Some(span) = tcx.def_ident_span(def_id) {
let name = tcx.item_name(def_id);
err.span_note(span, format!("type parameter `{name}` defined here"));
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::TyParam(def_id),
);
self.lower_ty_param(hir_id)
}
Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
let _ = self.prohibit_generic_args(
path.segments.iter(),
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
err.span_suggestion_verbose(
GenericsArgsErrExtend::SelfTyParam(
ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MaybeIncorrect,
);
}
});
)
} else {
GenericsArgsErrExtend::None
},
);
tcx.types.self_param
}
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
@ -1962,65 +1792,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assert_eq!(opt_self_ty, None);
// Try to evaluate any array length constants.
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
let span_of_impl = tcx.span_of_impl(def_id);
self.prohibit_generic_args(path.segments.iter(), |err| {
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did(),
_ => return,
};
let type_name = tcx.item_name(def_id);
let span_of_ty = tcx.def_ident_span(def_id);
let generics = tcx.generics_of(def_id).count();
let msg = format!("`Self` is of type `{ty}`");
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
let mut span: MultiSpan = vec![t_sp].into();
span.push_span_label(
i_sp,
format!("`Self` is on type `{type_name}` in this `impl`"),
);
let mut postfix = "";
if generics == 0 {
postfix = ", which doesn't have generic parameters";
}
span.push_span_label(
t_sp,
format!("`Self` corresponds to this type{postfix}"),
);
err.span_note(span, msg);
} else {
err.note(msg);
}
for segment in path.segments {
if let Some(args) = segment.args
&& segment.ident.name == kw::SelfUpper
{
if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MachineApplicable,
);
return;
} else {
err.span_suggestion_verbose(
segment.ident.span,
format!(
"the `Self` type doesn't accept type parameters, use the \
concrete type's name `{type_name}` instead if you want to \
specify its type parameters"
),
type_name,
Applicability::MaybeIncorrect,
);
}
}
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::SelfTyAlias { def_id, span },
);
// HACK(min_const_generics): Forbid generic `Self` types
// here as we can't easily do that during nameres.
//
@ -2061,7 +1836,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
ty::BoundConstness::ConstIfConst
@ -2079,19 +1857,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::PrimTy(prim_ty) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
let name = prim_ty.name_str();
for segment in path.segments {
if let Some(args) = segment.args {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
format!("primitive type `{name}` doesn't have generic parameters"),
"",
Applicability::MaybeIncorrect,
);
}
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::PrimTy(prim_ty),
);
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,

View file

@ -1,5 +1,4 @@
use crate::bounds::Bounds;
use crate::errors::TraitObjectDeclaredWithNoTraits;
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_err};
@ -86,47 +85,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1];
let mut err = struct_span_code_err!(
tcx.dcx(),
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
);
additional_trait.label_with_exp_info(
&mut err,
"additional non-auto trait",
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
err.help(format!(
"consider creating a new trait with all of these as supertraits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
));
err.note(
"auto-traits like `Send` and `Sync` are traits that have special properties; \
for more information on them, visit \
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
);
self.set_tainted_by_errors(err.emit());
}
if regular_traits.is_empty() && auto_traits.is_empty() {
let trait_alias_span = trait_bounds
.iter()
.map(|&(trait_ref, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
let reported =
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
self.set_tainted_by_errors(reported);
let _ = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() {
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, reported);
}

View file

@ -86,7 +86,7 @@ hir_typeck_invalid_callee = expected function, found {$ty}
hir_typeck_lossy_provenance_int2ptr =
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::with_exposed_provenance()` instead
hir_typeck_lossy_provenance_ptr2int =
under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`

View file

@ -11,6 +11,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
use rustc_hir_analysis::hir_ty_lowering::generics::{
check_generic_arg_count_for_call, lower_generic_args,
};
@ -1177,11 +1178,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let indices: FxHashSet<_> =
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
let generics_has_err = self.lowerer().prohibit_generic_args(
let generics_err = self.lowerer().prohibit_generic_args(
segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
}),
|_| {},
GenericsArgsErrExtend::None,
);
if let Res::Local(hid) = res {
@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return (ty, res);
}
if generics_has_err {
if let Err(_) = generics_err {
// Don't try to infer type parameters when prohibited generic arguments were given.
user_self_ty = None;
}

View file

@ -1916,22 +1916,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat: &'tcx hir::Pat<'tcx>,
ty: Ty<'tcx>,
) {
struct V {
pat_hir_ids: Vec<hir::HirId>,
}
impl<'tcx> Visitor<'tcx> for V {
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
self.pat_hir_ids.push(p.hir_id);
hir::intravisit::walk_pat(self, p);
}
}
if let Err(guar) = ty.error_reported() {
struct OverwritePatternsWithError {
pat_hir_ids: Vec<hir::HirId>,
}
impl<'tcx> Visitor<'tcx> for OverwritePatternsWithError {
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
self.pat_hir_ids.push(p.hir_id);
hir::intravisit::walk_pat(self, p);
}
}
// Override the types everywhere with `err()` to avoid knock on errors.
let err = Ty::new_error(self.tcx, guar);
self.write_ty(hir_id, err);
self.write_ty(pat.hir_id, err);
let mut visitor = V { pat_hir_ids: vec![] };
let mut visitor = OverwritePatternsWithError { pat_hir_ids: vec![] };
hir::intravisit::walk_pat(&mut visitor, pat);
// Mark all the subpatterns as `{type error}` as well. This allows errors for specific
// subpatterns to be silenced.

View file

@ -416,13 +416,13 @@ fn parse_never_type_options_attr(
continue;
}
if item.has_name(sym::diverging_block_default) && fallback.is_none() {
let mode = item.value_str().unwrap();
match mode {
if item.has_name(sym::diverging_block_default) && block.is_none() {
let default = item.value_str().unwrap();
match default {
sym::unit => block = Some(DivergingBlockBehavior::Unit),
sym::never => block = Some(DivergingBlockBehavior::Never),
_ => {
tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{mode}` (supported: `unit` and `never`)"));
tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{default}` (supported: `unit` and `never`)"));
}
};
continue;
@ -431,7 +431,7 @@ fn parse_never_type_options_attr(
tcx.dcx().span_err(
item.span(),
format!(
"unknown never type option: `{}` (supported: `fallback`)",
"unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
item.name_or_empty()
),
);

View file

@ -400,7 +400,7 @@ enum Chunk {
}
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
crate::static_assert_size!(Chunk, 16);
impl<T> ChunkedBitSet<T> {

View file

@ -483,7 +483,7 @@ pub enum SubregionOrigin<'tcx> {
}
// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(SubregionOrigin<'_>, 32);
impl<'tcx> SubregionOrigin<'tcx> {

View file

@ -32,7 +32,7 @@
#[macro_use]
extern crate rustc_macros;
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
#[macro_use]
extern crate rustc_data_structures;
#[macro_use]

View file

@ -112,7 +112,7 @@ impl<'tcx> PolyTraitObligation<'tcx> {
}
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(PredicateObligation<'_>, 48);
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;

View file

@ -2749,7 +2749,7 @@ declare_lint! {
/// memory the pointer is allowed to read/write. Casting an integer, which
/// doesn't have provenance, to a pointer requires the compiler to assign
/// (guess) provenance. The compiler assigns "all exposed valid" (see the
/// docs of [`ptr::from_exposed_addr`] for more information about this
/// docs of [`ptr::with_exposed_provenance`] for more information about this
/// "exposing"). This penalizes the optimiser and is not well suited for
/// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
/// platforms).
@ -2757,11 +2757,11 @@ declare_lint! {
/// It is much better to use [`ptr::with_addr`] instead to specify the
/// provenance you want. If using this function is not possible because the
/// code relies on exposed provenance then there is as an escape hatch
/// [`ptr::from_exposed_addr`].
/// [`ptr::with_exposed_provenance`].
///
/// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
/// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
/// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr.html
/// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
pub FUZZY_PROVENANCE_CASTS,
Allow,
"a fuzzy integer to pointer cast is used",

View file

@ -8,7 +8,7 @@ edition = "2021"
tracing = "0.1.28"
tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
tracing-tree = "0.2.0"
tracing-tree = "0.3.0"
# tidy-alphabetical-end
[dev-dependencies]

View file

@ -1,6 +1,7 @@
use crate::mir::mono::Linkage;
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Align;
use rustc_target::spec::SanitizerSet;
#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
@ -42,7 +43,7 @@ pub struct CodegenFnAttrs {
pub instruction_set: Option<InstructionSetAttr>,
/// The `#[repr(align(...))]` attribute. Indicates the value of which the function should be
/// aligned to.
pub alignment: Option<u32>,
pub alignment: Option<Align>,
}
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]

View file

@ -2,7 +2,7 @@
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.
use crate::ty::{TyCtxt, Visibility};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def::DefKind;
use rustc_macros::HashStable;
@ -90,7 +90,7 @@ impl EffectiveVisibility {
/// Holds a map of effective visibilities for reachable HIR nodes.
#[derive(Clone, Debug)]
pub struct EffectiveVisibilities<Id = LocalDefId> {
map: FxHashMap<Id, EffectiveVisibility>,
map: FxIndexMap<Id, EffectiveVisibility>,
}
impl EffectiveVisibilities {
@ -130,9 +130,8 @@ impl EffectiveVisibilities {
eff_vis: &EffectiveVisibility,
tcx: TyCtxt<'_>,
) {
use std::collections::hash_map::Entry;
match self.map.entry(def_id) {
Entry::Occupied(mut occupied) => {
IndexEntry::Occupied(mut occupied) => {
let old_eff_vis = occupied.get_mut();
for l in Level::all_levels() {
let vis_at_level = eff_vis.at_level(l);
@ -145,7 +144,7 @@ impl EffectiveVisibilities {
}
old_eff_vis
}
Entry::Vacant(vacant) => vacant.insert(*eff_vis),
IndexEntry::Vacant(vacant) => vacant.insert(*eff_vis),
};
}

View file

@ -70,7 +70,7 @@ pub enum ConstValue<'tcx> {
},
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(ConstValue<'_>, 24);
impl<'tcx> ConstValue<'tcx> {

View file

@ -88,7 +88,7 @@ pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
/// This is needed in `thir::pattern::lower_inline_const`.
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(InterpErrorInfo<'_>, 8);
/// Packages the kind of error we got from the const code interpreter

View file

@ -37,7 +37,7 @@ pub enum Scalar<Prov = CtfeProvenance> {
Ptr(Pointer<Prov>, u8),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(Scalar, 24);
// We want the `Debug` output to be readable as it is used by `derive(Debug)` for

View file

@ -1881,7 +1881,7 @@ impl DefLocation {
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -276,7 +276,7 @@ pub struct ClosureOutlivesRequirement<'tcx> {
}
// Make sure this enum doesn't unintentionally grow
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
/// Outlives-constraints can be categorized to determine whether and why they

View file

@ -426,7 +426,7 @@ impl<'tcx> Rvalue<'tcx> {
| CastKind::FnPtrToPtr
| CastKind::PtrToPtr
| CastKind::PointerCoercion(_)
| CastKind::PointerFromExposedAddress
| CastKind::PointerWithExposedProvenance
| CastKind::DynStar
| CastKind::Transmute,
_,

View file

@ -1312,8 +1312,8 @@ pub enum CastKind {
/// See the docs on `expose_addr` for more details.
PointerExposeAddress,
/// An address-to-pointer cast that picks up an exposed provenance.
/// See the docs on `from_exposed_addr` for more details.
PointerFromExposedAddress,
/// See the docs on `with_exposed_provenance` for more details.
PointerWithExposedProvenance,
/// Pointer related casts that are done by coercions. Note that reference-to-raw-ptr casts are
/// translated into `&raw mut/const *r`, i.e., they are not actually casts.
PointerCoercion(PointerCoercion),
@ -1438,12 +1438,22 @@ pub enum BinOp {
Ge,
/// The `>` operator (greater than)
Gt,
/// The `<=>` operator (three-way comparison, like `Ord::cmp`)
///
/// This is supported only on the integer types and `char`, always returning
/// [`rustc_hir::LangItem::OrderingEnum`] (aka [`std::cmp::Ordering`]).
///
/// [`Rvalue::BinaryOp`]`(BinOp::Cmp, A, B)` returns
/// - `Ordering::Less` (`-1_i8`, as a Scalar) if `A < B`
/// - `Ordering::Equal` (`0_i8`, as a Scalar) if `A == B`
/// - `Ordering::Greater` (`+1_i8`, as a Scalar) if `A > B`
Cmp,
/// The `ptr.offset` operator
Offset,
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
// tidy-alphabetical-start

View file

@ -14,7 +14,7 @@ pub struct PlaceTy<'tcx> {
}
// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(PlaceTy<'_>, 16);
impl<'tcx> PlaceTy<'tcx> {
@ -276,6 +276,11 @@ impl<'tcx> BinOp {
&BinOp::Eq | &BinOp::Lt | &BinOp::Le | &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
tcx.types.bool
}
&BinOp::Cmp => {
// these should be integer-like types of the same size.
assert_eq!(lhs_ty, rhs_ty);
tcx.ty_ordering_enum(None)
}
}
}
}
@ -312,7 +317,8 @@ impl BinOp {
BinOp::Gt => hir::BinOpKind::Gt,
BinOp::Le => hir::BinOpKind::Le,
BinOp::Ge => hir::BinOpKind::Ge,
BinOp::AddUnchecked
BinOp::Cmp
| BinOp::AddUnchecked
| BinOp::SubUnchecked
| BinOp::MulUnchecked
| BinOp::ShlUnchecked

View file

@ -339,7 +339,7 @@ macro_rules! define_callbacks {
pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
// Ensure that keys grow no larger than 64 bytes
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
const _: () = {
if mem::size_of::<Key<'static>>() > 64 {
panic!("{}", concat!(
@ -353,7 +353,7 @@ macro_rules! define_callbacks {
};
// Ensure that values grow no larger than 64 bytes
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
const _: () = {
if mem::size_of::<Value<'static>>() > 64 {
panic!("{}", concat!(

View file

@ -1204,7 +1204,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
// tidy-alphabetical-start

View file

@ -550,7 +550,7 @@ impl<'tcx> ObligationCauseCode<'tcx> {
}
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(ObligationCauseCode<'_>, 48);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -193,7 +193,6 @@ pub enum SelectionCandidate<'tcx> {
/// The evaluation results are ordered:
/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
/// implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent`
/// - `EvaluatedToErr` implies `EvaluatedToErrStackDependent`
/// - the "union" of evaluation results is equal to their maximum -
/// all the "potential success" candidates can potentially succeed,
/// so they are noops when unioned with a definite error, and within
@ -219,52 +218,9 @@ pub enum EvaluationResult {
/// variables. We are somewhat imprecise there, so we don't actually
/// know the real result.
///
/// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`.
/// This can't be trivially cached because the result depends on the
/// stack results.
EvaluatedToAmbigStackDependent,
/// Evaluation failed because we encountered an obligation we are already
/// trying to prove on this branch.
///
/// We know this branch can't be a part of a minimal proof-tree for
/// the "root" of our cycle, because then we could cut out the recursion
/// and maintain a valid proof tree. However, this does not mean
/// that all the obligations on this branch do not hold -- it's possible
/// that we entered this branch "speculatively", and that there
/// might be some other way to prove this obligation that does not
/// go through this cycle -- so we can't cache this as a failure.
///
/// For example, suppose we have this:
///
/// ```rust,ignore (pseudo-Rust)
/// pub trait Trait { fn xyz(); }
/// // This impl is "useless", but we can still have
/// // an `impl Trait for SomeUnsizedType` somewhere.
/// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
///
/// pub fn foo<T: Trait + ?Sized>() {
/// <T as Trait>::xyz();
/// }
/// ```
///
/// When checking `foo`, we have to prove `T: Trait`. This basically
/// translates into this:
///
/// ```plain,ignore
/// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
/// ```
///
/// When we try to prove it, we first go the first option, which
/// recurses. This shows us that the impl is "useless" -- it won't
/// tell us that `T: Trait` unless it already implemented `Trait`
/// by some other means. However, that does not prevent `T: Trait`
/// does not hold, because of the bound (which can indeed be satisfied
/// by `SomeUnsizedType` from another crate).
//
// FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we
// ought to convert it to an `EvaluatedToErr`, because we know
// there definitely isn't a proof tree for that obligation. Not
// doing so is still sound -- there isn't any proof tree, so the
// branch still can't be a part of a minimal one -- but does not re-enable caching.
EvaluatedToErrStackDependent,
/// Evaluation failed.
EvaluatedToErr,
}
@ -290,13 +246,13 @@ impl EvaluationResult {
| EvaluatedToAmbig
| EvaluatedToAmbigStackDependent => true,
EvaluatedToErr | EvaluatedToErrStackDependent => false,
EvaluatedToErr => false,
}
}
pub fn is_stack_dependent(self) -> bool {
match self {
EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true,
EvaluatedToAmbigStackDependent => true,
EvaluatedToOkModuloOpaqueTypes
| EvaluatedToOk

View file

@ -85,7 +85,7 @@ pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKin
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
mir::CastKind::PointerExposeAddress
}
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerFromExposedAddress,
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
(_, Some(CastTy::DynStar)) => mir::CastKind::DynStar,
(Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
(Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,

View file

@ -59,7 +59,7 @@ pub struct ConstData<'tcx> {
pub kind: ConstKind<'tcx>,
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(ConstData<'_>, 40);
impl<'tcx> Const<'tcx> {

View file

@ -71,8 +71,8 @@ pub enum Expr<'tcx> {
Cast(CastKind, Const<'tcx>, Ty<'tcx>),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(Expr<'_>, 24);
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
static_assert_size!(super::ConstKind<'_>, 32);

View file

@ -956,6 +956,13 @@ impl<'tcx> TyCtxt<'tcx> {
self.get_lang_items(())
}
/// Gets a `Ty` representing the [`LangItem::OrderingEnum`]
#[track_caller]
pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> {
let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span);
self.type_of(ordering_enum).no_bound_vars().unwrap()
}
/// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to
/// compare against another `DefId`, since `is_diagnostic_item` is cheaper.
pub fn get_diagnostic_item(self, name: Symbol) -> Option<DefId> {

View file

@ -1034,9 +1034,11 @@ impl PlaceholderLike for PlaceholderConst {
}
}
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
/// When interacting with the type system we must provide information about the
/// environment. `ParamEnv` is the type that represents this information. See the
/// [dev guide chapter][param_env_guide] for more information.
///
/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct ParamEnv<'tcx> {
/// This packs both caller bounds and the reveal enum into one pointer.
@ -1103,8 +1105,11 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ParamEnv<'tcx> {
impl<'tcx> ParamEnv<'tcx> {
/// Construct a trait environment suitable for contexts where
/// there are no where-clauses in scope. Hidden types (like `impl
/// Trait`) are left hidden, so this is suitable for ordinary
/// type-checking.
/// Trait`) are left hidden. In majority of cases it is incorrect
/// to use an empty environment. See the [dev guide section][param_env_guide]
/// for information on what a `ParamEnv` is and how to acquire one.
///
/// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html
#[inline]
pub fn empty() -> Self {
Self::new(List::empty(), Reveal::UserFacing)
@ -1552,7 +1557,6 @@ impl<'tcx> TyCtxt<'tcx> {
attr::ReprRust => ReprFlags::empty(),
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked(pack) => {
let pack = Align::from_bytes(pack as u64).unwrap();
min_pack = Some(if let Some(min_pack) = min_pack {
min_pack.min(pack)
} else {
@ -1584,7 +1588,7 @@ impl<'tcx> TyCtxt<'tcx> {
ReprFlags::empty()
}
attr::ReprAlign(align) => {
max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap()));
max_align = max_align.max(Some(align));
ReprFlags::empty()
}
});
@ -2164,7 +2168,7 @@ pub struct DestructuredConst<'tcx> {
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -2699,7 +2699,7 @@ impl<'tcx> VarianceDiagInfo<'tcx> {
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -1270,9 +1270,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) {
let mut split_or_candidate = false;
for candidate in &mut *candidates {
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
&*candidate.match_pairs
{
if let [MatchPair { test_case: TestCase::Or { .. }, .. }] = &*candidate.match_pairs {
// Split a candidate in which the only match-pair is an or-pattern into multiple
// candidates. This is so that
//
@ -1282,9 +1280,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// }
//
// only generates a single switch.
candidate.subcandidates = self.create_or_subcandidates(pats, candidate.has_guard);
let first_match_pair = candidate.match_pairs.pop().unwrap();
candidate.or_span = Some(first_match_pair.pattern.span);
let match_pair = candidate.match_pairs.pop().unwrap();
self.create_or_subcandidates(candidate, match_pair);
split_or_candidate = true;
}
}
@ -1297,7 +1294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
for candidate in candidates.iter_mut() {
candidate.visit_leaves(|leaf_candidate| new_candidates.push(leaf_candidate));
}
self.match_simplified_candidates(
self.match_candidates(
span,
scrutinee_span,
start_block,
@ -1472,14 +1469,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
return;
}
let match_pairs = mem::take(&mut first_candidate.match_pairs);
let (first_match_pair, remaining_match_pairs) = match_pairs.split_first().unwrap();
let TestCase::Or { ref pats } = &first_match_pair.test_case else { unreachable!() };
let first_match_pair = first_candidate.match_pairs.remove(0);
let remaining_match_pairs = mem::take(&mut first_candidate.match_pairs);
let remainder_start = self.cfg.start_new_block();
let or_span = first_match_pair.pattern.span;
// Test the alternatives of this or-pattern.
self.test_or_pattern(first_candidate, start_block, remainder_start, pats, or_span);
self.test_or_pattern(first_candidate, start_block, remainder_start, first_match_pair);
if !remaining_match_pairs.is_empty() {
// If more match pairs remain, test them after each subcandidate.
@ -1514,25 +1508,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
}
#[instrument(
skip(self, start_block, otherwise_block, or_span, candidate, pats),
level = "debug"
)]
#[instrument(skip(self, start_block, otherwise_block, candidate, match_pair), level = "debug")]
fn test_or_pattern<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
start_block: BasicBlock,
otherwise_block: BasicBlock,
pats: &[FlatPat<'pat, 'tcx>],
or_span: Span,
match_pair: MatchPair<'pat, 'tcx>,
) {
debug!("candidate={:#?}\npats={:#?}", candidate, pats);
let mut or_candidates: Vec<_> = pats
.iter()
.cloned()
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
.collect();
let mut or_candidate_refs: Vec<_> = or_candidates.iter_mut().collect();
let or_span = match_pair.pattern.span;
self.create_or_subcandidates(candidate, match_pair);
let mut or_candidate_refs: Vec<_> = candidate.subcandidates.iter_mut().collect();
self.match_candidates(
or_span,
or_span,
@ -1540,30 +1526,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
otherwise_block,
&mut or_candidate_refs,
);
candidate.subcandidates = or_candidates;
candidate.or_span = Some(or_span);
self.merge_trivial_subcandidates(candidate);
}
/// Try to merge all of the subcandidates of the given candidate into one.
/// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
/// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new
/// subcandidate. Any candidate that has been expanded that way should be passed to
/// `merge_trivial_subcandidates` after its subcandidates have been processed.
fn create_or_subcandidates<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
match_pair: MatchPair<'pat, 'tcx>,
) {
let TestCase::Or { pats } = match_pair.test_case else { bug!() };
debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);
candidate.or_span = Some(match_pair.pattern.span);
candidate.subcandidates = pats
.into_vec()
.into_iter()
.map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))
.collect();
}
/// Try to merge all of the subcandidates of the given candidate into one. This avoids
/// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The or-pattern should have
/// been expanded with `create_or_subcandidates`.
fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
if candidate.subcandidates.is_empty() || candidate.has_guard {
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
return;
}
let mut can_merge = true;
// Not `Iterator::all` because we don't want to short-circuit.
for subcandidate in &mut candidate.subcandidates {
self.merge_trivial_subcandidates(subcandidate);
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
can_merge &=
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty();
}
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
let can_merge = candidate.subcandidates.iter().all(|subcandidate| {
subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty()
});
if can_merge {
let any_matches = self.cfg.start_new_block();
let or_span = candidate.or_span.take().unwrap();

View file

@ -12,7 +12,7 @@
//! sort of test: for example, testing which variant an enum is, or
//! testing a value against a constant.
use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase};
use crate::build::matches::{MatchPair, PatternExtraData, TestCase};
use crate::build::Builder;
use std::mem;
@ -66,27 +66,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
debug!(simplified = ?match_pairs, "simplify_match_pairs");
}
/// Create a new candidate for each pattern in `pats`, and recursively simplify tje
/// single-or-pattern case.
pub(super) fn create_or_subcandidates<'pat>(
&mut self,
pats: &[FlatPat<'pat, 'tcx>],
has_guard: bool,
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
.cloned()
.map(|flat_pat| {
let mut candidate = Candidate::from_flat_pat(flat_pat, has_guard);
if let [MatchPair { test_case: TestCase::Or { pats, .. }, .. }] =
&*candidate.match_pairs
{
candidate.subcandidates = self.create_or_subcandidates(pats, has_guard);
let first_match_pair = candidate.match_pairs.pop().unwrap();
candidate.or_span = Some(first_match_pair.pattern.span);
}
candidate
})
.collect()
}
}

View file

@ -3,7 +3,7 @@
//! be a coroutine body that takes all of its upvars by-move, and which we stash
//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures.
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::UnordSet;
use rustc_hir as hir;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::{self, dump_mir, MirPass};
@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
return;
}
let mut by_ref_fields = FxIndexSet::default();
let mut by_ref_fields = UnordSet::default();
let by_move_upvars = Ty::new_tup_from_iter(
tcx,
tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| {
@ -73,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
struct MakeByMoveBody<'tcx> {
tcx: TyCtxt<'tcx>,
by_ref_fields: FxIndexSet<FieldIdx>,
by_ref_fields: UnordSet<FieldIdx>,
by_move_coroutine_ty: Ty<'tcx>,
}
@ -89,11 +89,11 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
location: mir::Location,
) {
if place.local == ty::CAPTURE_STRUCT_LOCAL
&& !place.projection.is_empty()
&& let mir::ProjectionElem::Field(idx, ty) = place.projection[0]
&& let Some((&mir::ProjectionElem::Field(idx, ty), projection)) =
place.projection.split_first()
&& self.by_ref_fields.contains(&idx)
{
let (begin, end) = place.projection[1..].split_first().unwrap();
let (begin, end) = projection.split_first().unwrap();
// FIXME(async_closures): I'm actually a bit surprised to see that we always
// initially deref the by-ref upvars. If this is not actually true, then we
// will at least get an ICE that explains why this isn't true :^)

View file

@ -90,6 +90,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
sym::wrapping_add
| sym::wrapping_sub
| sym::wrapping_mul
| sym::three_way_compare
| sym::unchecked_add
| sym::unchecked_sub
| sym::unchecked_mul
@ -109,6 +110,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
sym::wrapping_add => BinOp::Add,
sym::wrapping_sub => BinOp::Sub,
sym::wrapping_mul => BinOp::Mul,
sym::three_way_compare => BinOp::Cmp,
sym::unchecked_add => BinOp::AddUnchecked,
sym::unchecked_sub => BinOp::SubUnchecked,
sym::unchecked_mul => BinOp::MulUnchecked,

View file

@ -525,6 +525,7 @@ impl<'tcx> Validator<'_, 'tcx> {
| BinOp::Lt
| BinOp::Ge
| BinOp::Gt
| BinOp::Cmp
| BinOp::Offset
| BinOp::Add
| BinOp::AddUnchecked

View file

@ -14,6 +14,7 @@ use rustc_middle::ty::adjustment::CustomCoerceUnsized;
use rustc_middle::ty::Instance;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::def_id::DefId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::ErrorGuaranteed;
@ -57,13 +58,24 @@ fn custom_coerce_unsize_info<'tcx>(
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
/// unlinkable calls.
///
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
) -> bool {
!instance.def_id().is_local()
fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
name.as_str().starts_with("llvm.")
} else {
false
}
}
let def_id = instance.def_id();
!def_id.is_local()
&& tcx.is_compiler_builtins(LOCAL_CRATE)
&& tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none()
&& !is_llvm_intrinsic(tcx, def_id)
&& !should_codegen_locally(tcx, instance)
}

View file

@ -30,7 +30,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char};
//
// This assertion is in this crate, rather than in `rustc_lexer`, because that
// crate cannot depend on `rustc_data_structures`.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
#[derive(Clone, Debug)]

View file

@ -454,7 +454,7 @@ fn make_token_stream(
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -179,7 +179,7 @@ pub struct Parser<'a> {
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
// it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Parser<'_>, 264);
/// Stores span information about a closure.

View file

@ -1087,7 +1087,7 @@ fn unescape_string(string: &str) -> Option<string::String> {
}
// Assert a reasonable size for `Piece`
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
rustc_index::static_assert_size!(Piece<'_>, 16);
#[cfg(test)]

View file

@ -24,7 +24,7 @@ tracing = "0.1"
[dev-dependencies]
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "ansi"] }
tracing-tree = "0.2.0"
tracing-tree = "0.3.0"
[features]
default = ["rustc"]

View file

@ -155,13 +155,13 @@ use std::iter::once;
use smallvec::SmallVec;
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
use rustc_index::bit_set::GrowableBitSet;
use rustc_index::bit_set::{BitSet, GrowableBitSet};
use rustc_index::IndexVec;
use self::Constructor::*;
use self::MaybeInfiniteInt::*;
use self::SliceKind::*;
use crate::index;
use crate::PatCx;
/// Whether we have seen a constructor in the column or not.
@ -920,10 +920,7 @@ pub enum ConstructorSet<Cx: PatCx> {
Struct { empty: bool },
/// This type has the following list of constructors. If `variants` is empty and
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
Variants {
variants: index::IdxContainer<Cx::VariantIdx, VariantVisibility>,
non_exhaustive: bool,
},
Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
/// The type is `&T`.
Ref,
/// The type is a union.
@ -1025,7 +1022,7 @@ impl<Cx: PatCx> ConstructorSet<Cx> {
}
}
ConstructorSet::Variants { variants, non_exhaustive } => {
let mut seen_set = index::IdxSet::new_empty(variants.len());
let mut seen_set = BitSet::new_empty(variants.len());
for idx in seen.iter().filter_map(|c| c.as_variant()) {
seen_set.insert(idx);
}

View file

@ -25,50 +25,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
use std::fmt;
#[cfg(feature = "rustc")]
pub mod index {
// Faster version when the indices of variants are `0..variants.len()`.
pub use rustc_index::bit_set::BitSet as IdxSet;
pub use rustc_index::Idx;
pub use rustc_index::IndexVec as IdxContainer;
}
#[cfg(not(feature = "rustc"))]
pub mod index {
// Slower version when the indices of variants are something else.
pub trait Idx: Copy + PartialEq + Eq + std::hash::Hash {}
impl<T: Copy + PartialEq + Eq + std::hash::Hash> Idx for T {}
#[derive(Debug)]
pub struct IdxContainer<K, V>(pub rustc_hash::FxHashMap<K, V>);
impl<K: Idx, V> IdxContainer<K, V> {
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter_enumerated(&self) -> impl Iterator<Item = (K, &V)> {
self.0.iter().map(|(k, v)| (*k, v))
}
}
impl<V> FromIterator<V> for IdxContainer<usize, V> {
fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
Self(iter.into_iter().enumerate().collect())
}
}
#[derive(Debug)]
pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
impl<T: Idx> IdxSet<T> {
pub fn new_empty(_len: usize) -> Self {
Self(Default::default())
}
pub fn contains(&self, elem: T) -> bool {
self.0.contains(&elem)
}
pub fn insert(&mut self, elem: T) {
self.0.insert(elem);
}
}
}
// Re-exports to avoid rustc_index version issues.
pub use rustc_index::Idx;
pub use rustc_index::IndexVec;
#[cfg(feature = "rustc")]
use rustc_middle::ty::Ty;
@ -96,7 +55,7 @@ pub trait PatCx: Sized + fmt::Debug {
/// Errors that can abort analysis.
type Error: fmt::Debug;
/// The index of an enum variant.
type VariantIdx: Clone + index::Idx + fmt::Debug;
type VariantIdx: Clone + Idx + fmt::Debug;
/// A string literal
type StrLit: Clone + PartialEq + fmt::Debug;
/// Extra data to store in a match arm.

View file

@ -268,7 +268,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
use rustc_middle::mir::CastKind::*;
match self {
PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
PointerWithExposedProvenance => stable_mir::mir::CastKind::PointerWithExposedProvenance,
PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable(tables)),
DynStar => stable_mir::mir::CastKind::DynStar,
IntToInt => stable_mir::mir::CastKind::IntToInt,
@ -493,6 +493,7 @@ impl<'tcx> Stable<'tcx> for mir::BinOp {
BinOp::Ne => stable_mir::mir::BinOp::Ne,
BinOp::Ge => stable_mir::mir::BinOp::Ge,
BinOp::Gt => stable_mir::mir::BinOp::Gt,
BinOp::Cmp => stable_mir::mir::BinOp::Cmp,
BinOp::Offset => stable_mir::mir::BinOp::Offset,
}
}

View file

@ -1675,7 +1675,6 @@ symbols! {
simd_fmin,
simd_fpow,
simd_fpowi,
simd_from_exposed_addr,
simd_fsin,
simd_fsqrt,
simd_gather,
@ -1714,6 +1713,7 @@ symbols! {
simd_shuffle_generic,
simd_sub,
simd_trunc,
simd_with_exposed_provenance,
simd_xor,
since,
sinf128,
@ -1813,6 +1813,7 @@ symbols! {
thread,
thread_local,
thread_local_macro,
three_way_compare,
thumb2,
thumb_mode: "thumb-mode",
tmm_reg,

View file

@ -1218,22 +1218,35 @@ pub fn typeid_for_instance<'tcx>(
let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
let tuple_args =
tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
(trait_id, tuple_args)
(trait_id, Some(tuple_args))
}
ty::Coroutine(..) => (
tcx.require_lang_item(LangItem::Coroutine, None),
instance.args.as_coroutine().resume_ty(),
),
ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
hir::CoroutineKind::Coroutine(..) => (
tcx.require_lang_item(LangItem::Coroutine, None),
Some(instance.args.as_coroutine().resume_ty()),
),
hir::CoroutineKind::Desugared(desugaring, _) => {
let lang_item = match desugaring {
hir::CoroutineDesugaring::Async => LangItem::Future,
hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
hir::CoroutineDesugaring::Gen => LangItem::Iterator,
};
(tcx.require_lang_item(lang_item, None), None)
}
},
ty::CoroutineClosure(..) => (
tcx.require_lang_item(LangItem::FnOnce, None),
tcx.instantiate_bound_regions_with_erased(
instance.args.as_coroutine_closure().coroutine_closure_sig(),
)
.tupled_inputs_ty,
Some(
tcx.instantiate_bound_regions_with_erased(
instance.args.as_coroutine_closure().coroutine_closure_sig(),
)
.tupled_inputs_ty,
),
),
x => bug!("Unexpected type kind for closure-like: {x:?}"),
};
let trait_ref = ty::TraitRef::new(tcx, trait_id, [closure_ty, inputs]);
let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
// There should be exactly one method on this trait, and it should be the one we're

View file

@ -927,7 +927,7 @@ impl FromStr for Conv {
}
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;

View file

@ -49,8 +49,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// - the parameter environment
///
/// Invokes `evaluate_obligation`, so in the event that evaluating
/// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent
/// (or EvaluatedToAmbigStackDependent) will be returned.
/// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned.
#[instrument(level = "debug", skip(self, params), ret)]
fn type_implements_trait(
&self,

View file

@ -30,7 +30,7 @@
#[macro_use]
extern crate rustc_macros;
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_pointer_width = "64"))]
#[macro_use]
extern crate rustc_data_structures;
#[macro_use]

View file

@ -6,13 +6,13 @@ use super::*;
use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::traits::project::ProjectAndUnifyResult;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
use rustc_data_structures::unord::UnordSet;
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::{Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use std::collections::hash_map::Entry;
use std::collections::VecDeque;
use std::iter;
@ -25,8 +25,8 @@ pub enum RegionTarget<'tcx> {
#[derive(Default, Debug, Clone)]
pub struct RegionDeps<'tcx> {
larger: FxIndexSet<RegionTarget<'tcx>>,
smaller: FxIndexSet<RegionTarget<'tcx>>,
pub larger: FxIndexSet<RegionTarget<'tcx>>,
pub smaller: FxIndexSet<RegionTarget<'tcx>>,
}
pub enum AutoTraitResult<A> {
@ -35,17 +35,10 @@ pub enum AutoTraitResult<A> {
NegativeImpl,
}
#[allow(dead_code)]
impl<A> AutoTraitResult<A> {
fn is_auto(&self) -> bool {
matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
}
}
pub struct AutoTraitInfo<'cx> {
pub full_user_env: ty::ParamEnv<'cx>,
pub region_data: RegionConstraintData<'cx>,
pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>,
pub vid_to_region: FxIndexMap<ty::RegionVid, ty::Region<'cx>>,
}
pub struct AutoTraitFinder<'tcx> {
@ -88,19 +81,12 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
for polarity in [true, false] {
for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
let result = selcx.select(&Obligation::new(
tcx,
ObligationCause::dummy(),
orig_env,
ty::TraitPredicate {
trait_ref,
polarity: if polarity {
ty::PredicatePolarity::Positive
} else {
ty::PredicatePolarity::Negative
},
},
ty::TraitPredicate { trait_ref, polarity },
));
if let Ok(Some(ImplSource::UserDefined(_))) = result {
debug!(
@ -114,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
let infcx = tcx.infer_ctxt().build();
let mut fresh_preds = FxHashSet::default();
let mut fresh_preds = FxIndexSet::default();
// Due to the way projections are handled by SelectionContext, we need to run
// evaluate_predicates twice: once on the original param env, and once on the result of
@ -239,7 +225,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
user_env: ty::ParamEnv<'tcx>,
fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
let tcx = infcx.tcx;
@ -252,7 +238,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let mut select = SelectionContext::new(infcx);
let mut already_visited = FxHashSet::default();
let mut already_visited = UnordSet::new();
let mut predicates = VecDeque::new();
predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
@ -473,9 +459,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
fn map_vid_to_region<'cx>(
&self,
regions: &RegionConstraintData<'cx>,
) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> {
let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default();
let mut finished_map = FxHashMap::default();
) -> FxIndexMap<ty::RegionVid, ty::Region<'cx>> {
let mut vid_map = FxIndexMap::<RegionTarget<'cx>, RegionDeps<'cx>>::default();
let mut finished_map = FxIndexMap::default();
for (constraint, _) in &regions.constraints {
match constraint {
@ -513,25 +499,22 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
while !vid_map.is_empty() {
#[allow(rustc::potential_query_instability)]
let target = *vid_map.keys().next().expect("Keys somehow empty");
let deps = vid_map.remove(&target).expect("Entry somehow missing");
let target = *vid_map.keys().next().unwrap();
let deps = vid_map.swap_remove(&target).unwrap();
for smaller in deps.smaller.iter() {
for larger in deps.larger.iter() {
match (smaller, larger) {
(&RegionTarget::Region(_), &RegionTarget::Region(_)) => {
if let Entry::Occupied(v) = vid_map.entry(*smaller) {
if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
let smaller_deps = v.into_mut();
smaller_deps.larger.insert(*larger);
// FIXME(#120456) - is `swap_remove` correct?
smaller_deps.larger.swap_remove(&target);
}
if let Entry::Occupied(v) = vid_map.entry(*larger) {
if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
let larger_deps = v.into_mut();
larger_deps.smaller.insert(*smaller);
// FIXME(#120456) - is `swap_remove` correct?
larger_deps.smaller.swap_remove(&target);
}
}
@ -542,17 +525,15 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// Do nothing; we don't care about regions that are smaller than vids.
}
(&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
if let Entry::Occupied(v) = vid_map.entry(*smaller) {
if let IndexEntry::Occupied(v) = vid_map.entry(*smaller) {
let smaller_deps = v.into_mut();
smaller_deps.larger.insert(*larger);
// FIXME(#120456) - is `swap_remove` correct?
smaller_deps.larger.swap_remove(&target);
}
if let Entry::Occupied(v) = vid_map.entry(*larger) {
if let IndexEntry::Occupied(v) = vid_map.entry(*larger) {
let larger_deps = v.into_mut();
larger_deps.smaller.insert(*smaller);
// FIXME(#120456) - is `swap_remove` correct?
larger_deps.smaller.swap_remove(&target);
}
}
@ -560,6 +541,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
}
}
}
finished_map
}
@ -588,7 +570,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
ty: Ty<'_>,
nested: impl Iterator<Item = PredicateObligation<'tcx>>,
computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
fresh_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
selcx: &mut SelectionContext<'_, 'tcx>,
) -> bool {

View file

@ -210,7 +210,7 @@ fn overlap<'tcx>(
.intercrate(true)
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
.build();
let selcx = &mut SelectionContext::with_treat_inductive_cycle_as_ambig(&infcx);
let selcx = &mut SelectionContext::new(&infcx);
if track_ambiguity_causes.is_yes() {
selcx.enable_tracking_intercrate_ambiguity_causes();
}

Some files were not shown because too many files have changed in this diff Show more