Merge from rustc
This commit is contained in:
commit
22382ebd5c
583 changed files with 12875 additions and 9896 deletions
39
Cargo.lock
39
Cargo.lock
|
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -650,7 +650,7 @@ fn codegen_stmt<'tcx>(
|
|||
| CastKind::FnPtrToPtr
|
||||
| CastKind::PtrToPtr
|
||||
| CastKind::PointerExposeAddress
|
||||
| CastKind::PointerFromExposedAddress,
|
||||
| CastKind::PointerWithExposedProvenance,
|
||||
ref operand,
|
||||
to_ty,
|
||||
) => {
|
||||
|
|
|
|||
|
|
@ -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!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 = ®ular_traits[0];
|
||||
let additional_trait = ®ular_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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 = ®ular_traits[0];
|
||||
let additional_trait = ®ular_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(®ular_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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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>>;
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
| CastKind::FnPtrToPtr
|
||||
| CastKind::PtrToPtr
|
||||
| CastKind::PointerCoercion(_)
|
||||
| CastKind::PointerFromExposedAddress
|
||||
| CastKind::PointerWithExposedProvenance
|
||||
| CastKind::DynStar
|
||||
| CastKind::Transmute,
|
||||
_,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 :^)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -525,6 +525,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
| BinOp::Lt
|
||||
| BinOp::Ge
|
||||
| BinOp::Gt
|
||||
| BinOp::Cmp
|
||||
| BinOp::Offset
|
||||
| BinOp::Add
|
||||
| BinOp::AddUnchecked
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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 ®ions.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 {
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue