mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 06:26:55 +00:00
Auto merge of #139482 - Zalathar:rollup-h2ht1y6, r=Zalathar
Rollup of 9 pull requests Successful merges: - #139035 (Add new `PatKind::Missing` variants) - #139108 (Simplify `thir::PatKind::ExpandedConstant`) - #139112 (Implement `super let`) - #139365 (Default auto traits: fix perf) - #139397 (coverage: Build the CGU's global file table as late as possible) - #139455 ( Remove support for `extern "rust-intrinsic"` blocks) - #139461 (Stop calling `source_span` query in significant drop order code) - #139465 (add sret handling for scalar autodiff) - #139466 (Trivial tweaks to stop tracking source span directly) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e643f59f6d
@ -60,7 +60,6 @@ pub enum ExternAbi {
|
||||
System {
|
||||
unwind: bool,
|
||||
},
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
/// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even
|
||||
/// normally ABI-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
@ -128,7 +127,6 @@ abi_impls! {
|
||||
RiscvInterruptS =><= "riscv-interrupt-s",
|
||||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustIntrinsic =><= "rust-intrinsic",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
@ -199,7 +197,7 @@ impl ExternAbi {
|
||||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
use ExternAbi::*;
|
||||
matches!(self, Rust | RustCall | RustIntrinsic | RustCold)
|
||||
matches!(self, Rust | RustCall | RustCold)
|
||||
}
|
||||
|
||||
pub fn supports_varargs(self) -> bool {
|
||||
|
@ -563,6 +563,7 @@ impl Pat {
|
||||
/// This is intended for use by diagnostics.
|
||||
pub fn to_ty(&self) -> Option<P<Ty>> {
|
||||
let kind = match &self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
// In a type expression `_` is an inference variable.
|
||||
PatKind::Wild => TyKind::Infer,
|
||||
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
|
||||
@ -625,7 +626,8 @@ impl Pat {
|
||||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
// These patterns do not contain subpatterns, skip.
|
||||
PatKind::Wild
|
||||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Rest
|
||||
| PatKind::Never
|
||||
| PatKind::Expr(_)
|
||||
@ -676,6 +678,7 @@ impl Pat {
|
||||
/// Return a name suitable for diagnostics.
|
||||
pub fn descr(&self) -> Option<String> {
|
||||
match &self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
@ -769,6 +772,9 @@ pub enum RangeSyntax {
|
||||
// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PatKind {
|
||||
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
|
||||
Missing,
|
||||
|
||||
/// Represents a wildcard pattern (`_`).
|
||||
Wild,
|
||||
|
||||
@ -1169,6 +1175,7 @@ pub enum MacStmtStyle {
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Local {
|
||||
pub id: NodeId,
|
||||
pub super_: Option<Span>,
|
||||
pub pat: P<Pat>,
|
||||
pub ty: Option<P<Ty>>,
|
||||
pub kind: LocalKind,
|
||||
@ -3926,7 +3933,7 @@ mod size_asserts {
|
||||
static_assert_size!(Item, 144);
|
||||
static_assert_size!(ItemKind, 80);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 80);
|
||||
static_assert_size!(Local, 96);
|
||||
static_assert_size!(MetaItemLit, 40);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 72);
|
||||
|
@ -92,6 +92,12 @@ pub struct AutoDiffAttrs {
|
||||
pub input_activity: Vec<DiffActivity>,
|
||||
}
|
||||
|
||||
impl AutoDiffAttrs {
|
||||
pub fn has_primal_ret(&self) -> bool {
|
||||
matches!(self.ret_activity, DiffActivity::Active | DiffActivity::Dual)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffMode {
|
||||
pub fn is_rev(&self) -> bool {
|
||||
matches!(self, DiffMode::Reverse)
|
||||
|
@ -704,7 +704,8 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare
|
||||
}
|
||||
|
||||
fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
|
||||
let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
visit_opt(super_, |sp| vis.visit_span(sp));
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
@ -1587,7 +1588,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
||||
vis.visit_id(id);
|
||||
match kind {
|
||||
PatKind::Err(_guar) => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Ident(_binding_mode, ident, sub) => {
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
|
@ -323,7 +323,7 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::R
|
||||
}
|
||||
|
||||
pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result {
|
||||
let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
|
||||
let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_pat(pat));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
@ -750,7 +750,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
try_visit!(visitor.visit_expr(guard_condition));
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Err(_guar) => {}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
|
@ -95,6 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
|
||||
// Let statements are allowed to have impl trait in bindings.
|
||||
let super_ = l.super_;
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let span = self.lower_span(l.span);
|
||||
let source = hir::LocalSource::Normal;
|
||||
self.lower_attrs(hir_id, &l.attrs, l.span);
|
||||
self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
|
||||
self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source })
|
||||
}
|
||||
|
||||
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
|
||||
|
@ -1496,18 +1496,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
|
||||
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
if ident.name != kw::Empty {
|
||||
Some(self.lower_ident(ident))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
PatKind::Missing => None,
|
||||
PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)),
|
||||
PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
|
||||
_ => {
|
||||
self.dcx().span_delayed_bug(
|
||||
param.pat.span,
|
||||
"non-ident/wild param pat must trigger an error",
|
||||
"non-missing/ident/wild param pat must trigger an error",
|
||||
);
|
||||
None
|
||||
}
|
||||
@ -2223,6 +2218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::LetStmt {
|
||||
super_: None,
|
||||
hir_id,
|
||||
init,
|
||||
pat,
|
||||
|
@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||
let node = loop {
|
||||
match &pattern.kind {
|
||||
PatKind::Missing => break hir::PatKind::Missing,
|
||||
PatKind::Wild => break hir::PatKind::Wild,
|
||||
PatKind::Never => break hir::PatKind::Never,
|
||||
PatKind::Ident(binding_mode, ident, sub) => {
|
||||
|
@ -79,10 +79,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
||||
| ExternAbi::SysV64 { .. }
|
||||
| ExternAbi::System { .. }
|
||||
| ExternAbi::EfiApi => Ok(()),
|
||||
// implementation details
|
||||
ExternAbi::RustIntrinsic => {
|
||||
Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
|
||||
}
|
||||
ExternAbi::Unadjusted => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
for Param { pat, .. } in &decl.inputs {
|
||||
match pat.kind {
|
||||
PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
|
||||
PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
|
||||
PatKind::Ident(BindingMode::MUT, ident, None) => {
|
||||
report_err(pat.span, Some(ident), true)
|
||||
}
|
||||
|
@ -1336,6 +1336,9 @@ impl<'a> State<'a> {
|
||||
self.print_outer_attributes(&loc.attrs);
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
if loc.super_.is_some() {
|
||||
self.word_nbsp("super");
|
||||
}
|
||||
self.word_nbsp("let");
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
@ -1622,9 +1625,9 @@ impl<'a> State<'a> {
|
||||
fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
/* Pat isn't normalized, but the beauty of it
|
||||
is that it doesn't matter */
|
||||
/* Pat isn't normalized, but the beauty of it is that it doesn't matter */
|
||||
match &pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
|
||||
@ -1946,12 +1949,7 @@ impl<'a> State<'a> {
|
||||
if let Some(eself) = input.to_self() {
|
||||
self.print_explicit_self(&eself);
|
||||
} else {
|
||||
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
|
||||
ident.name == kw::Empty
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !invalid {
|
||||
if !matches!(input.pat.kind, PatKind::Missing) {
|
||||
self.print_pat(&input.pat);
|
||||
self.word(":");
|
||||
self.space();
|
||||
|
@ -22,7 +22,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument, trace};
|
||||
use tracing::{Level, debug, enabled, instrument, trace};
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
|
||||
@ -327,11 +327,13 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
||||
let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
|
||||
var_to_origin_sorted.sort_by_key(|vto| vto.0);
|
||||
|
||||
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
|
||||
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
|
||||
reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
|
||||
if enabled!(Level::DEBUG) {
|
||||
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
|
||||
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
|
||||
reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
|
||||
}
|
||||
debug!("{}", reg_vars_to_origins_str);
|
||||
}
|
||||
debug!("{}", reg_vars_to_origins_str);
|
||||
|
||||
let num_components = sccs.num_sccs();
|
||||
let mut components = vec![FxIndexSet::default(); num_components];
|
||||
@ -342,16 +344,18 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
||||
components[scc_idx.as_usize()].insert((reg_var, *origin));
|
||||
}
|
||||
|
||||
let mut components_str = "strongly connected components:".to_string();
|
||||
for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
|
||||
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
|
||||
components_str.push_str(&format!(
|
||||
"{:?}: {:?},\n)",
|
||||
ConstraintSccIndex::from_usize(scc_idx),
|
||||
regions_info,
|
||||
))
|
||||
if enabled!(Level::DEBUG) {
|
||||
let mut components_str = "strongly connected components:".to_string();
|
||||
for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
|
||||
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
|
||||
components_str.push_str(&format!(
|
||||
"{:?}: {:?},\n)",
|
||||
ConstraintSccIndex::from_usize(scc_idx),
|
||||
regions_info,
|
||||
))
|
||||
}
|
||||
debug!("{}", components_str);
|
||||
}
|
||||
debug!("{}", components_str);
|
||||
|
||||
// calculate the best representative for each component
|
||||
let components_representatives = components
|
||||
|
@ -1,5 +1,4 @@
|
||||
//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`,
|
||||
//! functions marked with the `#[rustc_intrinsic]` attribute
|
||||
//! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute
|
||||
//! and LLVM intrinsics that have symbol names starting with `llvm.`.
|
||||
|
||||
macro_rules! intrinsic_args {
|
||||
|
@ -201,7 +201,23 @@ fn compute_enzyme_fn_ty<'ll>(
|
||||
}
|
||||
|
||||
if attrs.width == 1 {
|
||||
todo!("Handle sret for scalar ad");
|
||||
// Enzyme returns a struct of style:
|
||||
// `{ original_ret(if requested), float, float, ... }`
|
||||
let mut struct_elements = vec![];
|
||||
if attrs.has_primal_ret() {
|
||||
struct_elements.push(inner_ret_ty);
|
||||
}
|
||||
// Next, we push the list of active floats, since they will be lowered to `enzyme_out`,
|
||||
// and therefore part of the return struct.
|
||||
let param_tys = cx.func_params_types(fn_ty);
|
||||
for (act, param_ty) in attrs.input_activity.iter().zip(param_tys) {
|
||||
if matches!(act, DiffActivity::Active) {
|
||||
// Now find the float type at position i based on the fn_ty,
|
||||
// to know what (f16/f32/f64/...) to add to the struct.
|
||||
struct_elements.push(param_ty);
|
||||
}
|
||||
}
|
||||
ret_ty = cx.type_struct(&struct_elements, false);
|
||||
} else {
|
||||
// First we check if we also have to deal with the primal return.
|
||||
match attrs.mode {
|
||||
@ -388,7 +404,11 @@ fn generate_enzyme_call<'ll>(
|
||||
// now store the result of the enzyme call into the sret pointer.
|
||||
let sret_ptr = outer_args[0];
|
||||
let call_ty = cx.val_ty(call);
|
||||
assert_eq!(cx.type_kind(call_ty), TypeKind::Array);
|
||||
if attrs.width == 1 {
|
||||
assert_eq!(cx.type_kind(call_ty), TypeKind::Struct);
|
||||
} else {
|
||||
assert_eq!(cx.type_kind(call_ty), TypeKind::Array);
|
||||
}
|
||||
llvm::LLVMBuildStore(&builder.llbuilder, call, sret_ptr);
|
||||
}
|
||||
builder.ret_void();
|
||||
|
@ -53,13 +53,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
None => return,
|
||||
};
|
||||
|
||||
// The order of entries in this global file table needs to be deterministic,
|
||||
// and ideally should also be independent of the details of stable-hashing,
|
||||
// because coverage tests snapshots (`.cov-map`) can observe the order and
|
||||
// would need to be re-blessed if it changes. As long as those requirements
|
||||
// are satisfied, the order can be arbitrary.
|
||||
let mut global_file_table = GlobalFileTable::new();
|
||||
|
||||
let mut covfun_records = instances_used
|
||||
.iter()
|
||||
.copied()
|
||||
@ -67,17 +60,13 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
// order that doesn't depend on the stable-hash-based order in which
|
||||
// instances were visited during codegen.
|
||||
.sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name)
|
||||
.filter_map(|instance| prepare_covfun_record(tcx, &mut global_file_table, instance, true))
|
||||
.filter_map(|instance| prepare_covfun_record(tcx, instance, true))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// In a single designated CGU, also prepare covfun records for functions
|
||||
// in this crate that were instrumented for coverage, but are unused.
|
||||
if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
|
||||
unused::prepare_covfun_records_for_unused_functions(
|
||||
cx,
|
||||
&mut global_file_table,
|
||||
&mut covfun_records,
|
||||
);
|
||||
unused::prepare_covfun_records_for_unused_functions(cx, &mut covfun_records);
|
||||
}
|
||||
|
||||
// If there are no covfun records for this CGU, don't generate a covmap record.
|
||||
@ -89,68 +78,88 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Encode all filenames referenced by coverage mappings in this CGU.
|
||||
let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
|
||||
// The `llvm-cov` tool uses this hash to associate each covfun record with
|
||||
// its corresponding filenames table, since the final binary will typically
|
||||
// contain multiple covmap records from different compilation units.
|
||||
let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
|
||||
// Prepare the global file table for this CGU, containing all paths needed
|
||||
// by one or more covfun records.
|
||||
let global_file_table =
|
||||
GlobalFileTable::build(tcx, covfun_records.iter().flat_map(|c| c.all_source_files()));
|
||||
|
||||
for covfun in &covfun_records {
|
||||
covfun::generate_covfun_record(cx, filenames_hash, covfun)
|
||||
covfun::generate_covfun_record(cx, &global_file_table, covfun)
|
||||
}
|
||||
|
||||
// Generate the coverage map header, which contains the filenames used by
|
||||
// this CGU's coverage mappings, and store it in a well-known global.
|
||||
// (This is skipped if we returned early due to having no covfun records.)
|
||||
generate_covmap_record(cx, covmap_version, &filenames_buffer);
|
||||
generate_covmap_record(cx, covmap_version, &global_file_table.filenames_buffer);
|
||||
}
|
||||
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying source files.
|
||||
/// Maps "global" (per-CGU) file ID numbers to their underlying source file paths.
|
||||
#[derive(Debug)]
|
||||
struct GlobalFileTable {
|
||||
/// This "raw" table doesn't include the working dir, so a file's
|
||||
/// global ID is its index in this set **plus one**.
|
||||
raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
|
||||
raw_file_table: FxIndexMap<StableSourceFileId, String>,
|
||||
|
||||
/// The file table in encoded form (possibly compressed), which can be
|
||||
/// included directly in this CGU's `__llvm_covmap` record.
|
||||
filenames_buffer: Vec<u8>,
|
||||
|
||||
/// Truncated hash of the bytes in `filenames_buffer`.
|
||||
///
|
||||
/// The `llvm-cov` tool uses this hash to associate each covfun record with
|
||||
/// its corresponding filenames table, since the final binary will typically
|
||||
/// contain multiple covmap records from different compilation units.
|
||||
filenames_hash: u64,
|
||||
}
|
||||
|
||||
impl GlobalFileTable {
|
||||
fn new() -> Self {
|
||||
Self { raw_file_table: FxIndexMap::default() }
|
||||
}
|
||||
/// Builds a "global file table" for this CGU, mapping numeric IDs to
|
||||
/// path strings.
|
||||
fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator<Item = &'a SourceFile>) -> Self {
|
||||
let mut raw_file_table = FxIndexMap::default();
|
||||
|
||||
fn global_file_id_for_file(&mut self, file: &Arc<SourceFile>) -> GlobalFileId {
|
||||
// Ensure the given file has a table entry, and get its index.
|
||||
let entry = self.raw_file_table.entry(file.stable_id);
|
||||
let raw_id = entry.index();
|
||||
entry.or_insert_with(|| Arc::clone(file));
|
||||
for file in all_files {
|
||||
raw_file_table.entry(file.stable_id).or_insert_with(|| {
|
||||
file.name
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
});
|
||||
}
|
||||
|
||||
// The raw file table doesn't include an entry for the working dir
|
||||
// (which has ID 0), so add 1 to get the correct ID.
|
||||
GlobalFileId::from_usize(raw_id + 1)
|
||||
}
|
||||
// FIXME(Zalathar): Consider sorting the file table here, but maybe
|
||||
// only after adding filename support to coverage-dump, so that the
|
||||
// table order isn't directly visible in `.coverage-map` snapshots.
|
||||
|
||||
fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
|
||||
let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
|
||||
let mut table = Vec::with_capacity(raw_file_table.len() + 1);
|
||||
|
||||
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
|
||||
// requires setting the first filename to the compilation directory.
|
||||
// Since rustc generates coverage maps with relative paths, the
|
||||
// compilation directory can be combined with the relative paths
|
||||
// to get absolute paths, if needed.
|
||||
table.push(
|
||||
tcx.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy(),
|
||||
);
|
||||
// Since version 6 of the LLVM coverage mapping format, the first entry
|
||||
// in the global file table is treated as a base directory, used to
|
||||
// resolve any other entries that are stored as relative paths.
|
||||
let base_dir = tcx
|
||||
.sess
|
||||
.opts
|
||||
.working_dir
|
||||
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
|
||||
.to_string_lossy();
|
||||
table.push(base_dir.as_ref());
|
||||
|
||||
// Add the regular entries after the base directory.
|
||||
table.extend(self.raw_file_table.values().map(|file| {
|
||||
file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
|
||||
}));
|
||||
table.extend(raw_file_table.values().map(|name| name.as_str()));
|
||||
|
||||
llvm_cov::write_filenames_to_buffer(&table)
|
||||
// Encode the file table into a buffer, and get the hash of its encoded
|
||||
// bytes, so that we can embed that hash in `__llvm_covfun` records.
|
||||
let filenames_buffer = llvm_cov::write_filenames_to_buffer(&table);
|
||||
let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
|
||||
|
||||
Self { raw_file_table, filenames_buffer, filenames_hash }
|
||||
}
|
||||
|
||||
fn get_existing_id(&self, file: &SourceFile) -> Option<GlobalFileId> {
|
||||
let raw_id = self.raw_file_table.get_index_of(&file.stable_id)?;
|
||||
// The raw file table doesn't include an entry for the base dir
|
||||
// (which has ID 0), so add 1 to get the correct ID.
|
||||
Some(GlobalFileId::from_usize(raw_id + 1))
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,26 +175,31 @@ rustc_index::newtype_index! {
|
||||
struct LocalFileId {}
|
||||
}
|
||||
|
||||
/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
|
||||
/// file IDs.
|
||||
/// Holds a mapping from "local" (per-function) file IDs to their corresponding
|
||||
/// source files.
|
||||
#[derive(Debug, Default)]
|
||||
struct VirtualFileMapping {
|
||||
local_to_global: IndexVec<LocalFileId, GlobalFileId>,
|
||||
global_to_local: FxIndexMap<GlobalFileId, LocalFileId>,
|
||||
local_file_table: IndexVec<LocalFileId, Arc<SourceFile>>,
|
||||
}
|
||||
|
||||
impl VirtualFileMapping {
|
||||
fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId {
|
||||
*self
|
||||
.global_to_local
|
||||
.entry(global_file_id)
|
||||
.or_insert_with(|| self.local_to_global.push(global_file_id))
|
||||
fn push_file(&mut self, source_file: &Arc<SourceFile>) -> LocalFileId {
|
||||
self.local_file_table.push(Arc::clone(source_file))
|
||||
}
|
||||
|
||||
fn to_vec(&self) -> Vec<u32> {
|
||||
// This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`,
|
||||
// but it isn't hot or expensive enough to justify the extra unsafety.
|
||||
self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect()
|
||||
/// Resolves all of the filenames in this local file mapping to a list of
|
||||
/// global file IDs in its CGU, for inclusion in this function's
|
||||
/// `__llvm_covfun` record.
|
||||
///
|
||||
/// The global file IDs are returned as `u32` to make FFI easier.
|
||||
fn resolve_all(&self, global_file_table: &GlobalFileTable) -> Option<Vec<u32>> {
|
||||
self.local_file_table
|
||||
.iter()
|
||||
.map(|file| try {
|
||||
let id = global_file_table.get_existing_id(file)?;
|
||||
GlobalFileId::as_u32(id)
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
//! [^win]: On Windows the section name is `.lcovfun`.
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_abi::Align;
|
||||
use rustc_codegen_ssa::traits::{
|
||||
@ -15,7 +16,7 @@ use rustc_middle::mir::coverage::{
|
||||
MappingKind, Op,
|
||||
};
|
||||
use rustc_middle::ty::{Instance, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{SourceFile, Span};
|
||||
use rustc_target::spec::HasTargetSpec;
|
||||
use tracing::debug;
|
||||
|
||||
@ -37,9 +38,16 @@ pub(crate) struct CovfunRecord<'tcx> {
|
||||
regions: ffi::Regions,
|
||||
}
|
||||
|
||||
impl<'tcx> CovfunRecord<'tcx> {
|
||||
/// Iterator that yields all source files referred to by this function's
|
||||
/// coverage mappings. Used to build the global file table for the CGU.
|
||||
pub(crate) fn all_source_files(&self) -> impl Iterator<Item = &SourceFile> {
|
||||
self.virtual_file_mapping.local_file_table.iter().map(Arc::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
global_file_table: &mut GlobalFileTable,
|
||||
instance: Instance<'tcx>,
|
||||
is_used: bool,
|
||||
) -> Option<CovfunRecord<'tcx>> {
|
||||
@ -57,7 +65,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
|
||||
regions: ffi::Regions::default(),
|
||||
};
|
||||
|
||||
fill_region_tables(tcx, global_file_table, fn_cov_info, ids_info, &mut covfun);
|
||||
fill_region_tables(tcx, fn_cov_info, ids_info, &mut covfun);
|
||||
|
||||
if covfun.regions.has_no_regions() {
|
||||
debug!(?covfun, "function has no mappings to embed; skipping");
|
||||
@ -92,7 +100,6 @@ fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec<ffi::CounterExpression
|
||||
/// Populates the mapping region tables in the current function's covfun record.
|
||||
fn fill_region_tables<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
global_file_table: &mut GlobalFileTable,
|
||||
fn_cov_info: &'tcx FunctionCoverageInfo,
|
||||
ids_info: &'tcx CoverageIdsInfo,
|
||||
covfun: &mut CovfunRecord<'tcx>,
|
||||
@ -106,11 +113,7 @@ fn fill_region_tables<'tcx>(
|
||||
};
|
||||
let source_file = source_map.lookup_source_file(first_span.lo());
|
||||
|
||||
// Look up the global file ID for that file.
|
||||
let global_file_id = global_file_table.global_file_id_for_file(&source_file);
|
||||
|
||||
// Associate that global file ID with a local file ID for this function.
|
||||
let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
|
||||
let local_file_id = covfun.virtual_file_mapping.push_file(&source_file);
|
||||
|
||||
// In rare cases, _all_ of a function's spans are discarded, and coverage
|
||||
// codegen needs to handle that gracefully to avoid #133606.
|
||||
@ -179,7 +182,7 @@ fn fill_region_tables<'tcx>(
|
||||
/// as a global variable in the `__llvm_covfun` section.
|
||||
pub(crate) fn generate_covfun_record<'tcx>(
|
||||
cx: &CodegenCx<'_, 'tcx>,
|
||||
filenames_hash: u64,
|
||||
global_file_table: &GlobalFileTable,
|
||||
covfun: &CovfunRecord<'tcx>,
|
||||
) {
|
||||
let &CovfunRecord {
|
||||
@ -191,12 +194,19 @@ pub(crate) fn generate_covfun_record<'tcx>(
|
||||
ref regions,
|
||||
} = covfun;
|
||||
|
||||
let Some(local_file_table) = virtual_file_mapping.resolve_all(global_file_table) else {
|
||||
debug_assert!(
|
||||
false,
|
||||
"all local files should be present in the global file table: \
|
||||
global_file_table = {global_file_table:?}, \
|
||||
virtual_file_mapping = {virtual_file_mapping:?}"
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
// Encode the function's coverage mappings into a buffer.
|
||||
let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer(
|
||||
&virtual_file_mapping.to_vec(),
|
||||
expressions,
|
||||
regions,
|
||||
);
|
||||
let coverage_mapping_buffer =
|
||||
llvm_cov::write_function_mappings_to_buffer(&local_file_table, expressions, regions);
|
||||
|
||||
// A covfun record consists of four target-endian integers, followed by the
|
||||
// encoded mapping data in bytes. Note that the length field is 32 bits.
|
||||
@ -209,7 +219,7 @@ pub(crate) fn generate_covfun_record<'tcx>(
|
||||
cx.const_u64(func_name_hash),
|
||||
cx.const_u32(coverage_mapping_buffer.len() as u32),
|
||||
cx.const_u64(source_hash),
|
||||
cx.const_u64(filenames_hash),
|
||||
cx.const_u64(global_file_table.filenames_hash),
|
||||
cx.const_bytes(&coverage_mapping_buffer),
|
||||
],
|
||||
// This struct needs to be packed, so that the 32-bit length field
|
||||
|
@ -7,7 +7,6 @@ use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefIdSet;
|
||||
|
||||
use crate::common::CodegenCx;
|
||||
use crate::coverageinfo::mapgen::GlobalFileTable;
|
||||
use crate::coverageinfo::mapgen::covfun::{CovfunRecord, prepare_covfun_record};
|
||||
use crate::llvm;
|
||||
|
||||
@ -21,7 +20,6 @@ use crate::llvm;
|
||||
/// its embedded coverage data.
|
||||
pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>(
|
||||
cx: &CodegenCx<'_, 'tcx>,
|
||||
global_file_table: &mut GlobalFileTable,
|
||||
covfun_records: &mut Vec<CovfunRecord<'tcx>>,
|
||||
) {
|
||||
assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
|
||||
@ -33,7 +31,7 @@ pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>(
|
||||
// Try to create a covfun record for each unused function.
|
||||
let mut name_globals = Vec::with_capacity(unused_instances.len());
|
||||
covfun_records.extend(unused_instances.into_iter().filter_map(|unused| try {
|
||||
let record = prepare_covfun_record(cx.tcx, global_file_table, unused.instance, false)?;
|
||||
let record = prepare_covfun_record(cx.tcx, unused.instance, false)?;
|
||||
// If successful, also store its symbol name in a global constant.
|
||||
name_globals.push(cx.const_str(unused.symbol_name.name).0);
|
||||
record
|
||||
|
@ -6,8 +6,9 @@ Erroneous code example:
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
pub static atomic_singlethreadfence_seqcst: fn();
|
||||
extern "C" {
|
||||
#[rustc_intrinsic]
|
||||
pub static atomic_singlethreadfence_seqcst: unsafe fn();
|
||||
// error: intrinsic must be a function
|
||||
}
|
||||
|
||||
@ -22,9 +23,8 @@ error, just declare a function. Example:
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
pub fn atomic_singlethreadfence_seqcst(); // ok!
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn atomic_singlethreadfence_seqcst(); // ok!
|
||||
|
||||
fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
|
||||
```
|
||||
|
@ -230,6 +230,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
self.pat_ident(sp, ident)
|
||||
};
|
||||
let local = P(ast::Local {
|
||||
super_: None,
|
||||
pat,
|
||||
ty,
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
@ -245,6 +246,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
/// Generates `let _: Type;`, which is usually used for type assertions.
|
||||
pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
|
||||
let local = P(ast::Local {
|
||||
super_: None,
|
||||
pat: self.pat_wild(span),
|
||||
ty: Some(ty),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
|
@ -211,7 +211,7 @@ declare_features! (
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
/// Allows using the `rust-intrinsic`'s "ABI".
|
||||
/// Allows using the #[rustc_intrinsic] attribute.
|
||||
(internal, intrinsics, "1.0.0", None),
|
||||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||
(internal, lang_items, "1.0.0", None),
|
||||
@ -630,7 +630,7 @@ declare_features! (
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
|
||||
/// Allows `super let` statements.
|
||||
(incomplete, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
|
||||
(unstable, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
|
||||
/// Allows subtrait items to shadow supertrait items.
|
||||
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
|
||||
/// Allows using `#[thread_local]` on `static` items.
|
||||
|
@ -1555,6 +1555,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Missing => unreachable!(),
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
@ -1582,7 +1583,7 @@ impl<'hir> Pat<'hir> {
|
||||
|
||||
use PatKind::*;
|
||||
match self.kind {
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
|
||||
Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
@ -1720,6 +1721,9 @@ pub enum TyPatKind<'hir> {
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum PatKind<'hir> {
|
||||
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
|
||||
Missing,
|
||||
|
||||
/// Represents a wildcard pattern (i.e., `_`).
|
||||
Wild,
|
||||
|
||||
@ -1817,6 +1821,8 @@ pub enum StmtKind<'hir> {
|
||||
/// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct LetStmt<'hir> {
|
||||
/// Span of `super` in `super let`.
|
||||
pub super_: Option<Span>,
|
||||
pub pat: &'hir Pat<'hir>,
|
||||
/// Type annotation, if any (otherwise the type will be inferred).
|
||||
pub ty: Option<&'hir Ty<'hir>>,
|
||||
@ -4850,7 +4856,7 @@ mod size_asserts {
|
||||
static_assert_size!(ImplItemKind<'_>, 40);
|
||||
static_assert_size!(Item<'_>, 88);
|
||||
static_assert_size!(ItemKind<'_>, 64);
|
||||
static_assert_size!(LetStmt<'_>, 64);
|
||||
static_assert_size!(LetStmt<'_>, 72);
|
||||
static_assert_size!(Param<'_>, 32);
|
||||
static_assert_size!(Pat<'_>, 72);
|
||||
static_assert_size!(Path<'_>, 40);
|
||||
|
@ -744,7 +744,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
||||
visit_opt!(visitor, visit_pat_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_pat_expr, upper_bound);
|
||||
}
|
||||
PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||
PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
|
||||
PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
|
||||
walk_list!(visitor, visit_pat, prepatterns);
|
||||
visit_opt!(visitor, visit_pat, slice_pattern);
|
||||
|
@ -741,10 +741,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
|
||||
for &assoc_item in assoc_items.in_definition_order() {
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Fn => {
|
||||
let abi = tcx.fn_sig(assoc_item.def_id).skip_binder().abi();
|
||||
forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi);
|
||||
}
|
||||
ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
|
||||
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
|
||||
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
|
||||
@ -788,65 +784,59 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
};
|
||||
check_abi(tcx, it.span, abi);
|
||||
|
||||
match abi {
|
||||
ExternAbi::RustIntrinsic => {
|
||||
for item in items {
|
||||
intrinsic::check_intrinsic_type(
|
||||
tcx,
|
||||
item.id.owner_id.def_id,
|
||||
item.span,
|
||||
item.ident.name,
|
||||
abi,
|
||||
);
|
||||
}
|
||||
for item in items {
|
||||
let def_id = item.id.owner_id.def_id;
|
||||
|
||||
if tcx.has_attr(def_id, sym::rustc_intrinsic) {
|
||||
intrinsic::check_intrinsic_type(
|
||||
tcx,
|
||||
item.id.owner_id.def_id,
|
||||
item.span,
|
||||
item.ident.name,
|
||||
abi,
|
||||
);
|
||||
}
|
||||
|
||||
_ => {
|
||||
for item in items {
|
||||
let def_id = item.id.owner_id.def_id;
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let own_counts = generics.own_counts();
|
||||
if generics.own_params.len() - own_counts.lifetimes != 0 {
|
||||
let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts)
|
||||
{
|
||||
(_, 0) => ("type", "types", Some("u32")),
|
||||
// We don't specify an example value, because we can't generate
|
||||
// a valid value for any type.
|
||||
(0, _) => ("const", "consts", None),
|
||||
_ => ("type or const", "types or consts", None),
|
||||
};
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
item.span,
|
||||
E0044,
|
||||
"foreign items may not have {kinds} parameters",
|
||||
)
|
||||
.with_span_label(item.span, format!("can't have {kinds} parameters"))
|
||||
.with_help(
|
||||
// FIXME: once we start storing spans for type arguments, turn this
|
||||
// into a suggestion.
|
||||
format!(
|
||||
"replace the {} parameters with concrete {}{}",
|
||||
kinds,
|
||||
kinds_pl,
|
||||
egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let own_counts = generics.own_counts();
|
||||
if generics.own_params.len() - own_counts.lifetimes != 0 {
|
||||
let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
|
||||
(_, 0) => ("type", "types", Some("u32")),
|
||||
// We don't specify an example value, because we can't generate
|
||||
// a valid value for any type.
|
||||
(0, _) => ("const", "consts", None),
|
||||
_ => ("type or const", "types or consts", None),
|
||||
};
|
||||
struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
item.span,
|
||||
E0044,
|
||||
"foreign items may not have {kinds} parameters",
|
||||
)
|
||||
.with_span_label(item.span, format!("can't have {kinds} parameters"))
|
||||
.with_help(
|
||||
// FIXME: once we start storing spans for type arguments, turn this
|
||||
// into a suggestion.
|
||||
format!(
|
||||
"replace the {} parameters with concrete {}{}",
|
||||
kinds,
|
||||
kinds_pl,
|
||||
egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
let item = tcx.hir_foreign_item(item.id);
|
||||
match &item.kind {
|
||||
hir::ForeignItemKind::Fn(sig, _, _) => {
|
||||
require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
|
||||
}
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
check_static_inhabited(tcx, def_id);
|
||||
check_static_linkage(tcx, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let item = tcx.hir_foreign_item(item.id);
|
||||
match &item.kind {
|
||||
hir::ForeignItemKind::Fn(sig, _, _) => {
|
||||
require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
|
||||
}
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
check_static_inhabited(tcx, def_id);
|
||||
check_static_linkage(tcx, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//! Type-checking for the rust-intrinsic intrinsics that the compiler exposes.
|
||||
//! Type-checking for the `#[rustc_intrinsic]` intrinsics that the compiler exposes.
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::codes::*;
|
||||
|
@ -137,15 +137,6 @@ fn get_owner_return_paths(
|
||||
})
|
||||
}
|
||||
|
||||
/// Forbid defining intrinsics in Rust code,
|
||||
/// as they must always be defined by the compiler.
|
||||
// FIXME: Move this to a more appropriate place.
|
||||
pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) {
|
||||
if let ExternAbi::RustIntrinsic = abi {
|
||||
tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
|
||||
// Only restricted on wasm target for now
|
||||
if !tcx.sess.target.is_like_wasm {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
use std::mem;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> {
|
||||
scope_tree: ScopeTree,
|
||||
|
||||
cx: Context,
|
||||
|
||||
extended_super_lets: FxHashMap<hir::ItemLocalId, Option<Scope>>,
|
||||
}
|
||||
|
||||
/// Records the lifetime of a local variable as `cx.var_parent`
|
||||
@ -214,18 +217,29 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi
|
||||
let stmt_id = stmt.hir_id.local_id;
|
||||
debug!("resolve_stmt(stmt.id={:?})", stmt_id);
|
||||
|
||||
// Every statement will clean up the temporaries created during
|
||||
// execution of that statement. Therefore each statement has an
|
||||
// associated destruction scope that represents the scope of the
|
||||
// statement plus its destructors, and thus the scope for which
|
||||
// regions referenced by the destructors need to survive.
|
||||
if let hir::StmtKind::Let(LetStmt { super_: Some(_), .. }) = stmt.kind {
|
||||
// `super let` statement does not start a new scope, such that
|
||||
//
|
||||
// { super let x = identity(&temp()); &x }.method();
|
||||
//
|
||||
// behaves exactly as
|
||||
//
|
||||
// (&identity(&temp()).method();
|
||||
intravisit::walk_stmt(visitor, stmt);
|
||||
} else {
|
||||
// Every statement will clean up the temporaries created during
|
||||
// execution of that statement. Therefore each statement has an
|
||||
// associated destruction scope that represents the scope of the
|
||||
// statement plus its destructors, and thus the scope for which
|
||||
// regions referenced by the destructors need to survive.
|
||||
|
||||
let prev_parent = visitor.cx.parent;
|
||||
visitor.enter_node_scope_with_dtor(stmt_id, true);
|
||||
let prev_parent = visitor.cx.parent;
|
||||
visitor.enter_node_scope_with_dtor(stmt_id, true);
|
||||
|
||||
intravisit::walk_stmt(visitor, stmt);
|
||||
intravisit::walk_stmt(visitor, stmt);
|
||||
|
||||
visitor.cx.parent = prev_parent;
|
||||
visitor.cx.parent = prev_parent;
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_expr<'tcx>(
|
||||
@ -478,14 +492,19 @@ fn resolve_expr<'tcx>(
|
||||
visitor.cx = prev_cx;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum LetKind {
|
||||
Regular,
|
||||
Super,
|
||||
}
|
||||
|
||||
fn resolve_local<'tcx>(
|
||||
visitor: &mut ScopeResolutionVisitor<'tcx>,
|
||||
pat: Option<&'tcx hir::Pat<'tcx>>,
|
||||
init: Option<&'tcx hir::Expr<'tcx>>,
|
||||
let_kind: LetKind,
|
||||
) {
|
||||
debug!("resolve_local(pat={:?}, init={:?})", pat, init);
|
||||
|
||||
let blk_scope = visitor.cx.var_parent;
|
||||
debug!("resolve_local(pat={:?}, init={:?}, let_kind={:?})", pat, init, let_kind);
|
||||
|
||||
// As an exception to the normal rules governing temporary
|
||||
// lifetimes, initializers in a let have a temporary lifetime
|
||||
@ -543,14 +562,50 @@ fn resolve_local<'tcx>(
|
||||
// A, but the inner rvalues `a()` and `b()` have an extended lifetime
|
||||
// due to rule C.
|
||||
|
||||
if let_kind == LetKind::Super {
|
||||
if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) {
|
||||
// This expression was lifetime-extended by a parent let binding. E.g.
|
||||
//
|
||||
// let a = {
|
||||
// super let b = temp();
|
||||
// &b
|
||||
// };
|
||||
//
|
||||
// (Which needs to behave exactly as: let a = &temp();)
|
||||
//
|
||||
// Processing of `let a` will have already decided to extend the lifetime of this
|
||||
// `super let` to its own var_scope. We use that scope.
|
||||
visitor.cx.var_parent = scope;
|
||||
} else {
|
||||
// This `super let` is not subject to lifetime extension from a parent let binding. E.g.
|
||||
//
|
||||
// identity({ super let x = temp(); &x }).method();
|
||||
//
|
||||
// (Which needs to behave exactly as: identity(&temp()).method();)
|
||||
//
|
||||
// Iterate up to the enclosing destruction scope to find the same scope that will also
|
||||
// be used for the result of the block itself.
|
||||
while let Some(s) = visitor.cx.var_parent {
|
||||
let parent = visitor.scope_tree.parent_map.get(&s).cloned();
|
||||
if let Some(Scope { data: ScopeData::Destruction, .. }) = parent {
|
||||
break;
|
||||
}
|
||||
visitor.cx.var_parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(expr) = init {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, expr, blk_scope);
|
||||
record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent);
|
||||
|
||||
if let Some(pat) = pat {
|
||||
if is_binding_pat(pat) {
|
||||
visitor.scope_tree.record_rvalue_candidate(
|
||||
expr.hir_id,
|
||||
RvalueCandidate { target: expr.hir_id.local_id, lifetime: blk_scope },
|
||||
RvalueCandidate {
|
||||
target: expr.hir_id.local_id,
|
||||
lifetime: visitor.cx.var_parent,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -562,6 +617,7 @@ fn resolve_local<'tcx>(
|
||||
if let Some(expr) = init {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
|
||||
if let Some(pat) = pat {
|
||||
visitor.visit_pat(pat);
|
||||
}
|
||||
@ -623,6 +679,7 @@ fn resolve_local<'tcx>(
|
||||
|
||||
PatKind::Ref(_, _)
|
||||
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
||||
| PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Expr(_)
|
||||
@ -639,6 +696,7 @@ fn resolve_local<'tcx>(
|
||||
/// | [ ..., E&, ... ]
|
||||
/// | ( ..., E&, ... )
|
||||
/// | {...; E&}
|
||||
/// | { super let ... = E&; ... }
|
||||
/// | if _ { ...; E& } else { ...; E& }
|
||||
/// | match _ { ..., _ => E&, ... }
|
||||
/// | box E&
|
||||
@ -675,6 +733,13 @@ fn resolve_local<'tcx>(
|
||||
if let Some(subexpr) = block.expr {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
||||
}
|
||||
for stmt in block.stmts {
|
||||
if let hir::StmtKind::Let(local) = stmt.kind
|
||||
&& let Some(_) = local.super_
|
||||
{
|
||||
visitor.extended_super_lets.insert(local.pat.hir_id.local_id, blk_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::If(_, then_block, else_block) => {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id);
|
||||
@ -800,7 +865,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
|
||||
local_id: body.value.hir_id.local_id,
|
||||
data: ScopeData::Destruction,
|
||||
});
|
||||
resolve_local(this, None, Some(body.value));
|
||||
resolve_local(this, None, Some(body.value), LetKind::Regular);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -818,7 +883,11 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
|
||||
resolve_expr(self, ex, false);
|
||||
}
|
||||
fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
|
||||
resolve_local(self, Some(l.pat), l.init)
|
||||
let let_kind = match l.super_ {
|
||||
Some(_) => LetKind::Super,
|
||||
None => LetKind::Regular,
|
||||
};
|
||||
resolve_local(self, Some(l.pat), l.init, let_kind);
|
||||
}
|
||||
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
|
||||
let body = self.tcx.hir_body(c.body);
|
||||
@ -847,6 +916,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
|
||||
cx: Context { parent: None, var_parent: None },
|
||||
pessimistic_yield: false,
|
||||
fixup_scopes: vec![],
|
||||
extended_super_lets: Default::default(),
|
||||
};
|
||||
|
||||
visitor.scope_tree.root_body = Some(body.value.hir_id);
|
||||
|
@ -42,7 +42,6 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::check::intrinsic::intrinsic_operation_unsafety;
|
||||
use crate::errors;
|
||||
use crate::hir_ty_lowering::errors::assoc_kind_str;
|
||||
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
|
||||
@ -1704,18 +1703,13 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
||||
abi: ExternAbi,
|
||||
safety: hir::Safety,
|
||||
) -> ty::PolyFnSig<'tcx> {
|
||||
let safety = if abi == ExternAbi::RustIntrinsic {
|
||||
intrinsic_operation_unsafety(tcx, def_id)
|
||||
} else {
|
||||
safety
|
||||
};
|
||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let fty =
|
||||
ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None);
|
||||
|
||||
// Feature gate SIMD types in FFI, since I am not sure that the
|
||||
// ABIs are handled at all correctly. -huonw
|
||||
if abi != ExternAbi::RustIntrinsic && !tcx.features().simd_ffi() {
|
||||
if !tcx.features().simd_ffi() {
|
||||
let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
|
||||
if ty.is_simd() {
|
||||
let snip = tcx
|
||||
|
@ -172,33 +172,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
};
|
||||
|
||||
if let Node::TraitItem(item) = node {
|
||||
let parent = tcx.local_parent(item.hir_id().owner.def_id);
|
||||
let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let (trait_generics, trait_bounds) = match parent_trait.kind {
|
||||
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
|
||||
// they are not added as super trait bounds to the trait itself. See comment on
|
||||
// `requires_default_supertraits` for more details.
|
||||
if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) {
|
||||
let mut bounds = Vec::new();
|
||||
let self_ty_where_predicates = (parent, item.generics.predicates);
|
||||
icx.lowerer().add_default_traits_with_filter(
|
||||
&mut bounds,
|
||||
tcx.types.self_param,
|
||||
&[],
|
||||
Some(self_ty_where_predicates),
|
||||
item.span,
|
||||
|tr| tr != hir::LangItem::Sized,
|
||||
);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
let mut bounds = Vec::new();
|
||||
icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
|
||||
predicates.extend(bounds);
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
@ -43,12 +43,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
|
||||
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
|
||||
/// or associative items.
|
||||
/// or associated items.
|
||||
///
|
||||
/// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
|
||||
/// should be added everywhere, including super bounds. However this causes a huge performance
|
||||
/// costs. For optimization purposes instead of adding default supertraits, bounds
|
||||
/// are added to the associative items:
|
||||
/// are added to the associated items:
|
||||
///
|
||||
/// ```ignore(illustrative)
|
||||
/// // Default bounds are generated in the following way:
|
||||
@ -81,7 +81,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
///
|
||||
/// Therefore, `experimental_default_bounds` are still being added to supertraits if
|
||||
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
|
||||
pub(crate) fn requires_default_supertraits(
|
||||
fn requires_default_supertraits(
|
||||
&self,
|
||||
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
|
||||
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||
@ -120,6 +120,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
found
|
||||
}
|
||||
|
||||
/// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
|
||||
/// they are not added as super trait bounds to the trait itself. See
|
||||
/// `requires_default_supertraits` for more information.
|
||||
pub(crate) fn add_default_trait_item_bounds(
|
||||
&self,
|
||||
trait_item: &hir::TraitItem<'tcx>,
|
||||
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
if !tcx.sess.opts.unstable_opts.experimental_default_bounds {
|
||||
return;
|
||||
}
|
||||
|
||||
let parent = tcx.local_parent(trait_item.hir_id().owner.def_id);
|
||||
let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let (trait_generics, trait_bounds) = match parent_trait.kind {
|
||||
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
|
||||
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.requires_default_supertraits(trait_bounds, trait_generics) {
|
||||
let self_ty_where_predicates = (parent, trait_item.generics.predicates);
|
||||
self.add_default_traits_with_filter(
|
||||
bounds,
|
||||
tcx.types.self_param,
|
||||
&[],
|
||||
Some(self_ty_where_predicates),
|
||||
trait_item.span,
|
||||
|tr| tr != hir::LangItem::Sized,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazily sets `experimental_default_bounds` to true on trait super bounds.
|
||||
/// See `requires_default_supertraits` for more information.
|
||||
pub(crate) fn add_default_super_traits(
|
||||
@ -130,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
hir_generics: &'tcx hir::Generics<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
|
||||
return;
|
||||
}
|
||||
|
||||
assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
|
||||
if self.requires_default_supertraits(hir_bounds, hir_generics) {
|
||||
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
|
||||
@ -263,11 +304,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
seen_unbound = true;
|
||||
}
|
||||
let emit_relax_err = || {
|
||||
let unbound_traits =
|
||||
match self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
|
||||
true => "`?Sized` and `experimental_default_bounds`",
|
||||
false => "`?Sized`",
|
||||
};
|
||||
let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
|
||||
true => "`?Sized` and `experimental_default_bounds`",
|
||||
false => "`?Sized`",
|
||||
};
|
||||
// There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
|
||||
tcx.dcx().span_err(
|
||||
unbound.span,
|
||||
|
@ -960,12 +960,16 @@ impl<'a> State<'a> {
|
||||
|
||||
fn print_local(
|
||||
&mut self,
|
||||
super_: bool,
|
||||
init: Option<&hir::Expr<'_>>,
|
||||
els: Option<&hir::Block<'_>>,
|
||||
decl: impl Fn(&mut Self),
|
||||
) {
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
if super_ {
|
||||
self.word_nbsp("super");
|
||||
}
|
||||
self.word_nbsp("let");
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
@ -995,7 +999,9 @@ impl<'a> State<'a> {
|
||||
self.maybe_print_comment(st.span.lo());
|
||||
match st.kind {
|
||||
hir::StmtKind::Let(loc) => {
|
||||
self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc));
|
||||
self.print_local(loc.super_.is_some(), loc.init, loc.els, |this| {
|
||||
this.print_local_decl(loc)
|
||||
});
|
||||
}
|
||||
hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
|
||||
hir::StmtKind::Expr(expr) => {
|
||||
@ -1488,7 +1494,7 @@ impl<'a> State<'a> {
|
||||
|
||||
// Print `let _t = $init;`:
|
||||
let temp = Ident::from_str("_t");
|
||||
self.print_local(Some(init), None, |this| this.print_ident(temp));
|
||||
self.print_local(false, Some(init), None, |this| this.print_ident(temp));
|
||||
self.word(";");
|
||||
|
||||
// Print `_t`:
|
||||
@ -1868,6 +1874,7 @@ impl<'a> State<'a> {
|
||||
// Pat isn't normalized, but the beauty of it
|
||||
// is that it doesn't matter
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
|
||||
|
@ -5,7 +5,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi};
|
||||
use rustc_hir_analysis::check::check_function_signature;
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_infer::traits::WellFormedLoc;
|
||||
use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
|
||||
@ -50,8 +50,6 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
|
||||
let span = body.value.span;
|
||||
|
||||
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
|
||||
|
||||
GatherLocalsVisitor::new(fcx).visit_body(body);
|
||||
|
||||
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
|
||||
|
@ -970,7 +970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
|
||||
|
||||
// Normalize only after registering in `user_provided_sigs`.
|
||||
self.normalize(self.tcx.hir_span(hir_id), result)
|
||||
self.normalize(self.tcx.def_span(expr_def_id), result)
|
||||
}
|
||||
|
||||
/// Invoked when we are translating the coroutine that results
|
||||
|
@ -37,7 +37,6 @@
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_attr_parsing::InlineAttr;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, struct_span_code_err};
|
||||
@ -1240,10 +1239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
|
||||
// Intrinsics are not coercible to function pointers.
|
||||
if a_sig.abi() == ExternAbi::RustIntrinsic || b_sig.abi() == ExternAbi::RustIntrinsic {
|
||||
return Err(TypeError::IntrinsicCast);
|
||||
}
|
||||
// The signature must match.
|
||||
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
|
||||
let sig = self
|
||||
|
@ -482,7 +482,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// All of these constitute a read, or match on something that isn't `!`,
|
||||
// which would require a `NeverToAny` coercion.
|
||||
hir::PatKind::Binding(_, _, _, _)
|
||||
hir::PatKind::Missing
|
||||
| hir::PatKind::Binding(_, _, _, _)
|
||||
| hir::PatKind::Struct(_, _, _)
|
||||
| hir::PatKind::TupleStruct(_, _, _)
|
||||
| hir::PatKind::Tuple(_, _)
|
||||
|
@ -611,6 +611,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||
for pat in pats {
|
||||
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
|
||||
match &pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Binding(.., opt_sub_pat) => {
|
||||
// If the opt_sub_pat is None, then the binding does not count as
|
||||
// a wildcard for the purpose of borrowing discr.
|
||||
@ -1832,6 +1833,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||
| PatKind::Expr(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
| PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Err(_) => {
|
||||
// always ok
|
||||
|
@ -43,7 +43,7 @@ pub(super) struct Declaration<'a> {
|
||||
|
||||
impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> {
|
||||
fn from(local: &'a hir::LetStmt<'a>) -> Self {
|
||||
let hir::LetStmt { hir_id, pat, ty, span, init, els, source: _ } = *local;
|
||||
let hir::LetStmt { hir_id, super_: _, pat, ty, span, init, els, source: _ } = *local;
|
||||
Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ fn typeck_with_inspect<'tcx>(
|
||||
|
||||
let id = tcx.local_def_id_to_hir_id(def_id);
|
||||
let node = tcx.hir_node(id);
|
||||
let span = tcx.hir_span(id);
|
||||
let span = tcx.def_span(def_id);
|
||||
|
||||
// Figure out what primary body this item has.
|
||||
let body_id = node.body_id().unwrap_or_else(|| {
|
||||
|
@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
let ty = match pat.kind {
|
||||
PatKind::Wild | PatKind::Err(_) => expected,
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
|
||||
// We allow any type here; we ensure that the type is uninhabited during match checking.
|
||||
PatKind::Never => expected,
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
|
||||
@ -505,9 +505,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
},
|
||||
|
||||
// Ref patterns are complicated, we handle them in `check_pat_ref`.
|
||||
PatKind::Ref(..) => AdjustMode::Pass,
|
||||
PatKind::Ref(..)
|
||||
// No need to do anything on a missing pattern.
|
||||
| PatKind::Missing
|
||||
// A `_` pattern works with any expected type, so there's no need to do anything.
|
||||
PatKind::Wild
|
||||
| PatKind::Wild
|
||||
// A malformed pattern doesn't have an expected type, so let's just accept any type.
|
||||
| PatKind::Err(_)
|
||||
// Bindings also work with whatever the expected type is,
|
||||
@ -1032,7 +1034,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
| PatKind::Tuple(..)
|
||||
| PatKind::Slice(..) => "binding",
|
||||
|
||||
PatKind::Wild
|
||||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Binding(..)
|
||||
| PatKind::Box(..)
|
||||
|
@ -779,21 +779,19 @@ impl EarlyLintPass for AnonymousParameters {
|
||||
}
|
||||
if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
|
||||
for arg in sig.decl.inputs.iter() {
|
||||
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
|
||||
if ident.name == kw::Empty {
|
||||
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
|
||||
if let ast::PatKind::Missing = arg.pat.kind {
|
||||
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
|
||||
|
||||
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
|
||||
(snip.as_str(), Applicability::MachineApplicable)
|
||||
} else {
|
||||
("<type>", Applicability::HasPlaceholders)
|
||||
};
|
||||
cx.emit_span_lint(
|
||||
ANONYMOUS_PARAMETERS,
|
||||
arg.pat.span,
|
||||
BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
|
||||
);
|
||||
}
|
||||
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
|
||||
(snip.as_str(), Applicability::MachineApplicable)
|
||||
} else {
|
||||
("<type>", Applicability::HasPlaceholders)
|
||||
};
|
||||
cx.emit_span_lint(
|
||||
ANONYMOUS_PARAMETERS,
|
||||
arg.pat.span,
|
||||
BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1201,7 +1201,8 @@ impl EarlyLintPass for UnusedParens {
|
||||
// Do not lint on `(..)` as that will result in the other arms being useless.
|
||||
Paren(_)
|
||||
// The other cases do not contain sub-patterns.
|
||||
| Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
|
||||
| Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None)
|
||||
| Path(..) | Err(_) => {},
|
||||
// These are list-like patterns; parens can always be removed.
|
||||
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
|
||||
self.check_unused_parens_pat(cx, p, false, false, keep_space);
|
||||
|
@ -207,7 +207,7 @@ impl<'tcx> Collector<'tcx> {
|
||||
|
||||
let sess = self.tcx.sess;
|
||||
|
||||
if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) {
|
||||
if matches!(abi, ExternAbi::Rust) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -747,6 +747,9 @@ pub struct Ascription<'tcx> {
|
||||
|
||||
#[derive(Clone, Debug, HashStable, TypeVisitable)]
|
||||
pub enum PatKind<'tcx> {
|
||||
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
|
||||
Missing,
|
||||
|
||||
/// A wildcard pattern: `_`.
|
||||
Wild,
|
||||
|
||||
@ -812,23 +815,17 @@ pub enum PatKind<'tcx> {
|
||||
},
|
||||
|
||||
/// Pattern obtained by converting a constant (inline or named) to its pattern
|
||||
/// representation using `const_to_pat`.
|
||||
/// representation using `const_to_pat`. This is used for unsafety checking.
|
||||
ExpandedConstant {
|
||||
/// [DefId] of the constant, we need this so that we have a
|
||||
/// reference that can be used by unsafety checking to visit nested
|
||||
/// unevaluated constants and for diagnostics. If the `DefId` doesn't
|
||||
/// correspond to a local crate, it points at the `const` item.
|
||||
/// [DefId] of the constant item.
|
||||
def_id: DefId,
|
||||
/// If `false`, then `def_id` points at a `const` item, otherwise it
|
||||
/// corresponds to a local inline const.
|
||||
is_inline: bool,
|
||||
/// If the inline constant is used in a range pattern, this subpattern
|
||||
/// represents the range (if both ends are inline constants, there will
|
||||
/// be multiple InlineConstant wrappers).
|
||||
/// The pattern that the constant lowered to.
|
||||
///
|
||||
/// Otherwise, the actual pattern that the constant lowered to. As with
|
||||
/// other constants, inline constants are matched structurally where
|
||||
/// possible.
|
||||
/// HACK: we need to keep the `DefId` of inline constants around for unsafety checking;
|
||||
/// therefore when a range pattern contains inline constants, we re-wrap the range pattern
|
||||
/// with the `ExpandedConstant` nodes that correspond to the range endpoints. Hence
|
||||
/// `subpattern` may actually be a range pattern, and `def_id` be the constant for one of
|
||||
/// its endpoints.
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
|
@ -250,7 +250,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
||||
mut callback: impl FnMut(&'a Pat<'tcx>),
|
||||
) {
|
||||
match &pat.kind {
|
||||
PatKind::Wild
|
||||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Binding { subpattern: None, .. }
|
||||
| PatKind::Constant { value: _ }
|
||||
| PatKind::Range(_)
|
||||
|
@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> {
|
||||
/// - coroutines
|
||||
Item(DefId),
|
||||
|
||||
/// An intrinsic `fn` item (with `"rust-intrinsic"` ABI).
|
||||
/// An intrinsic `fn` item (with`#[rustc_instrinsic]`).
|
||||
///
|
||||
/// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR.
|
||||
/// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
|
||||
|
@ -1265,9 +1265,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
|
||||
| CCmseNonSecureCall
|
||||
| CCmseNonSecureEntry
|
||||
| Unadjusted => false,
|
||||
Rust | RustCall | RustCold | RustIntrinsic => {
|
||||
tcx.sess.panic_strategy() == PanicStrategy::Unwind
|
||||
}
|
||||
Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,25 +143,11 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
|
||||
| ty::UnsafeBinder(_) => None,
|
||||
|
||||
ty::Adt(adt_def, _) => {
|
||||
let did = adt_def.did();
|
||||
let try_local_did_span = |did: DefId| {
|
||||
if let Some(local) = did.as_local() {
|
||||
tcx.source_span(local)
|
||||
} else {
|
||||
tcx.def_span(did)
|
||||
}
|
||||
};
|
||||
let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
|
||||
dtor.did
|
||||
} else if let Some(dtor) = tcx.adt_async_destructor(did) {
|
||||
return Some(tcx.source_span(dtor.impl_did));
|
||||
if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
|
||||
Some(tcx.def_span(tcx.parent(dtor.did)))
|
||||
} else {
|
||||
return Some(try_local_did_span(did));
|
||||
};
|
||||
let def_key = tcx.def_key(dtor);
|
||||
let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
|
||||
let parent_did = DefId { index: parent_index, krate: dtor.krate };
|
||||
Some(try_local_did_span(parent_did))
|
||||
Some(tcx.def_span(adt_def.did()))
|
||||
}
|
||||
}
|
||||
ty::Coroutine(did, _)
|
||||
| ty::CoroutineWitness(did, _)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::{fmt, iter};
|
||||
|
||||
use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size};
|
||||
use rustc_abi::{Float, Integer, IntegerType, Size};
|
||||
use rustc_apfloat::Float as _;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
@ -1719,10 +1719,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
/// the compiler to make some assumptions about its shape; if the user doesn't use a feature gate, they may
|
||||
/// cause an ICE that we otherwise may want to prevent.
|
||||
pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
|
||||
if tcx.features().intrinsics()
|
||||
&& (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
|
||||
|| tcx.has_attr(def_id, sym::rustc_intrinsic))
|
||||
{
|
||||
if tcx.features().intrinsics() && tcx.has_attr(def_id, sym::rustc_intrinsic) {
|
||||
let must_be_overridden = match tcx.hir_node_by_def_id(def_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
|
||||
!has_body
|
||||
|
@ -145,7 +145,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
|
||||
let arm = &self.thir[*arm];
|
||||
let value = match arm.pattern.kind {
|
||||
PatKind::Constant { value } => value,
|
||||
PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
|
||||
PatKind::ExpandedConstant { ref subpattern, def_id: _ }
|
||||
if let PatKind::Constant { value } = subpattern.kind =>
|
||||
{
|
||||
value
|
||||
|
@ -118,7 +118,7 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||
let place = place_builder.try_to_place(cx);
|
||||
let mut subpairs = Vec::new();
|
||||
let test_case = match pattern.kind {
|
||||
PatKind::Wild | PatKind::Error(_) => None,
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
|
||||
|
||||
PatKind::Or { ref pats } => Some(TestCase::Or {
|
||||
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
|
||||
@ -201,39 +201,10 @@ impl<'tcx> MatchPairTree<'tcx> {
|
||||
None
|
||||
}
|
||||
|
||||
PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
|
||||
PatKind::ExpandedConstant { subpattern: ref pattern, .. } => {
|
||||
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
|
||||
None
|
||||
}
|
||||
PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
|
||||
MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
|
||||
|
||||
// Apply a type ascription for the inline constant to the value at `match_pair.place`
|
||||
if let Some(source) = place {
|
||||
let span = pattern.span;
|
||||
let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id());
|
||||
let args = ty::InlineConstArgs::new(
|
||||
cx.tcx,
|
||||
ty::InlineConstArgsParts {
|
||||
parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
|
||||
ty: cx.infcx.next_ty_var(span),
|
||||
},
|
||||
)
|
||||
.args;
|
||||
let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new(
|
||||
ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }),
|
||||
));
|
||||
let annotation = ty::CanonicalUserTypeAnnotation {
|
||||
inferred_ty: pattern.ty,
|
||||
span,
|
||||
user_ty: Box::new(user_ty),
|
||||
};
|
||||
let variance = ty::Contravariant;
|
||||
extra_data.ascriptions.push(super::Ascription { annotation, source, variance });
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
PatKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
cx.prefix_slice_suffix(
|
||||
|
@ -920,6 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
PatKind::Constant { .. }
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Error(_) => {}
|
||||
|
@ -315,6 +315,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
|
||||
if self.in_union_destructure {
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
// binding to a variable allows getting stuff out of variable
|
||||
PatKind::Binding { .. }
|
||||
// match is conditional on having this value
|
||||
@ -403,9 +404,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
visit::walk_pat(self, pat);
|
||||
self.inside_adt = old_inside_adt;
|
||||
}
|
||||
PatKind::ExpandedConstant { def_id, is_inline, .. } => {
|
||||
PatKind::ExpandedConstant { def_id, .. } => {
|
||||
if let Some(def) = def_id.as_local()
|
||||
&& *is_inline
|
||||
&& matches!(self.tcx.def_kind(def_id), DefKind::InlineConst)
|
||||
{
|
||||
self.visit_inner_body(def);
|
||||
}
|
||||
|
@ -676,7 +676,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
unpeeled_pat = subpattern;
|
||||
}
|
||||
|
||||
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = unpeeled_pat.kind
|
||||
if let PatKind::ExpandedConstant { def_id, .. } = unpeeled_pat.kind
|
||||
&& let DefKind::Const = self.tcx.def_kind(def_id)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
|
||||
// We filter out paths with multiple path::segments.
|
||||
@ -1296,7 +1296,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
|
||||
|
||||
for &arm in arms {
|
||||
let arm = &thir.arms[arm];
|
||||
if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
|
||||
if let PatKind::ExpandedConstant { def_id, .. } = arm.pattern.kind
|
||||
&& !matches!(cx.tcx.def_kind(def_id), DefKind::InlineConst)
|
||||
&& let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
|
||||
// We filter out paths with multiple path::segments.
|
||||
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
|
||||
|
@ -182,7 +182,10 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
inlined_const_as_pat
|
||||
// Wrap the pattern in a marker node to indicate that it is the result of lowering a
|
||||
// constant. This is used for diagnostics, and for unsafety checking of inline const blocks.
|
||||
let kind = PatKind::ExpandedConstant { subpattern: inlined_const_as_pat, def_id: uv.def };
|
||||
Box::new(Pat { kind, ty, span: self.span })
|
||||
}
|
||||
|
||||
fn field_pats(
|
||||
|
@ -13,14 +13,15 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{self as hir, LangItem, RangeEnd};
|
||||
use rustc_index::Idx;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::interpret::LitToConstInput;
|
||||
use rustc_middle::thir::{
|
||||
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
||||
};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
@ -124,7 +125,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
expr: Option<&'tcx hir::PatExpr<'tcx>>,
|
||||
// Out-parameters collecting extra data to be reapplied by the caller
|
||||
ascriptions: &mut Vec<Ascription<'tcx>>,
|
||||
inline_consts: &mut Vec<LocalDefId>,
|
||||
expanded_consts: &mut Vec<DefId>,
|
||||
) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
|
||||
let Some(expr) = expr else { return Ok(None) };
|
||||
|
||||
@ -139,10 +140,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
ascriptions.push(ascription);
|
||||
kind = subpattern.kind;
|
||||
}
|
||||
PatKind::ExpandedConstant { is_inline, def_id, subpattern } => {
|
||||
if is_inline {
|
||||
inline_consts.extend(def_id.as_local());
|
||||
}
|
||||
PatKind::ExpandedConstant { def_id, subpattern } => {
|
||||
expanded_consts.push(def_id);
|
||||
kind = subpattern.kind;
|
||||
}
|
||||
_ => break,
|
||||
@ -221,10 +220,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
|
||||
// Collect extra data while lowering the endpoints, to be reapplied later.
|
||||
let mut ascriptions = vec![];
|
||||
let mut inline_consts = vec![];
|
||||
let mut expanded_consts = vec![];
|
||||
|
||||
let mut lower_endpoint =
|
||||
|expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut inline_consts);
|
||||
|expr| self.lower_pattern_range_endpoint(expr, &mut ascriptions, &mut expanded_consts);
|
||||
|
||||
let lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
|
||||
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity);
|
||||
@ -269,17 +268,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
// `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
|
||||
// constants somewhere. Have them on the range pattern.
|
||||
for ascription in ascriptions {
|
||||
kind = PatKind::AscribeUserType {
|
||||
ascription,
|
||||
subpattern: Box::new(Pat { span, ty, kind }),
|
||||
};
|
||||
let subpattern = Box::new(Pat { span, ty, kind });
|
||||
kind = PatKind::AscribeUserType { ascription, subpattern };
|
||||
}
|
||||
for def in inline_consts {
|
||||
kind = PatKind::ExpandedConstant {
|
||||
def_id: def.to_def_id(),
|
||||
is_inline: true,
|
||||
subpattern: Box::new(Pat { span, ty, kind }),
|
||||
};
|
||||
for def_id in expanded_consts {
|
||||
let subpattern = Box::new(Pat { span, ty, kind });
|
||||
kind = PatKind::ExpandedConstant { def_id, subpattern };
|
||||
}
|
||||
Ok(kind)
|
||||
}
|
||||
@ -290,6 +284,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
let mut span = pat.span;
|
||||
|
||||
let kind = match pat.kind {
|
||||
hir::PatKind::Missing => PatKind::Missing,
|
||||
|
||||
hir::PatKind::Wild => PatKind::Wild,
|
||||
|
||||
hir::PatKind::Never => PatKind::Never,
|
||||
@ -567,15 +563,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
// Lower the named constant to a THIR pattern.
|
||||
let args = self.typeck_results.node_args(id);
|
||||
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
|
||||
let subpattern = self.const_to_pat(c, ty, id, span);
|
||||
|
||||
// Wrap the pattern in a marker node to indicate that it is the result
|
||||
// of lowering a named constant. This marker is used for improved
|
||||
// diagnostics in some situations, but has no effect at runtime.
|
||||
let mut pattern = {
|
||||
let kind = PatKind::ExpandedConstant { subpattern, def_id, is_inline: false };
|
||||
Box::new(Pat { span, ty, kind })
|
||||
};
|
||||
let mut pattern = self.const_to_pat(c, ty, id, span);
|
||||
|
||||
// If this is an associated constant with an explicit user-written
|
||||
// type, add an ascription node (e.g. `<Foo<'a> as MyTrait>::CONST`).
|
||||
@ -612,18 +600,37 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
let ty = tcx.typeck(def_id).node_type(block.hir_id);
|
||||
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
|
||||
let parent_args =
|
||||
tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
|
||||
let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
|
||||
|
||||
debug_assert!(!args.has_free_regions());
|
||||
|
||||
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
|
||||
let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
|
||||
let c = ty::Const::new_unevaluated(self.tcx, ct);
|
||||
let pattern = self.const_to_pat(c, ty, id, span);
|
||||
|
||||
// Wrap the pattern in a marker node to indicate that it is the result
|
||||
// of lowering an inline const block.
|
||||
PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
|
||||
// Apply a type ascription for the inline constant.
|
||||
let annotation = {
|
||||
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let args = ty::InlineConstArgs::new(
|
||||
tcx,
|
||||
ty::InlineConstArgsParts { parent_args, ty: infcx.next_ty_var(span) },
|
||||
)
|
||||
.args;
|
||||
infcx.canonicalize_user_type_annotation(ty::UserType::new(ty::UserTypeKind::TypeOf(
|
||||
def_id.to_def_id(),
|
||||
ty::UserArgs { args, user_self_ty: None },
|
||||
)))
|
||||
};
|
||||
let annotation =
|
||||
CanonicalUserTypeAnnotation { user_ty: Box::new(annotation), span, inferred_ty: ty };
|
||||
PatKind::AscribeUserType {
|
||||
subpattern: pattern,
|
||||
ascription: Ascription {
|
||||
annotation,
|
||||
// Note that we use `Contravariant` here. See the `variance` field documentation
|
||||
// for details.
|
||||
variance: ty::Contravariant,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Lowers the kinds of "expression" that can appear in a HIR pattern:
|
||||
@ -635,43 +642,41 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
expr: &'tcx hir::PatExpr<'tcx>,
|
||||
pat_ty: Option<Ty<'tcx>>,
|
||||
) -> PatKind<'tcx> {
|
||||
let (lit, neg) = match &expr.kind {
|
||||
hir::PatExprKind::Path(qpath) => {
|
||||
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
|
||||
}
|
||||
match &expr.kind {
|
||||
hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
|
||||
hir::PatExprKind::ConstBlock(anon_const) => {
|
||||
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
|
||||
self.lower_inline_const(anon_const, expr.hir_id, expr.span)
|
||||
}
|
||||
hir::PatExprKind::Lit { lit, negated } => (lit, *negated),
|
||||
};
|
||||
|
||||
// We handle byte string literal patterns by using the pattern's type instead of the
|
||||
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
|
||||
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
|
||||
// pattern's type means we'll properly translate it to a slice reference pattern. This works
|
||||
// because slices and arrays have the same valtree representation.
|
||||
// HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
|
||||
// `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
|
||||
// FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
|
||||
// superseded by a more general implementation of deref patterns.
|
||||
let ct_ty = match pat_ty {
|
||||
Some(pat_ty)
|
||||
if let ty::Adt(def, _) = *pat_ty.kind()
|
||||
&& self.tcx.is_lang_item(def.did(), LangItem::String) =>
|
||||
{
|
||||
if !self.tcx.features().string_deref_patterns() {
|
||||
span_bug!(
|
||||
expr.span,
|
||||
"matching on `String` went through without enabling string_deref_patterns"
|
||||
);
|
||||
}
|
||||
self.typeck_results.node_type(expr.hir_id)
|
||||
hir::PatExprKind::Lit { lit, negated } => {
|
||||
// We handle byte string literal patterns by using the pattern's type instead of the
|
||||
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
|
||||
// the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
|
||||
// pattern's type means we'll properly translate it to a slice reference pattern. This works
|
||||
// because slices and arrays have the same valtree representation.
|
||||
// HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
|
||||
// `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
|
||||
// FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
|
||||
// superseded by a more general implementation of deref patterns.
|
||||
let ct_ty = match pat_ty {
|
||||
Some(pat_ty)
|
||||
if let ty::Adt(def, _) = *pat_ty.kind()
|
||||
&& self.tcx.is_lang_item(def.did(), LangItem::String) =>
|
||||
{
|
||||
if !self.tcx.features().string_deref_patterns() {
|
||||
span_bug!(
|
||||
expr.span,
|
||||
"matching on `String` went through without enabling string_deref_patterns"
|
||||
);
|
||||
}
|
||||
self.typeck_results.node_type(expr.hir_id)
|
||||
}
|
||||
Some(pat_ty) => pat_ty,
|
||||
None => self.typeck_results.node_type(expr.hir_id),
|
||||
};
|
||||
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated };
|
||||
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
|
||||
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
|
||||
}
|
||||
Some(pat_ty) => pat_ty,
|
||||
None => self.typeck_results.node_type(expr.hir_id),
|
||||
};
|
||||
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
|
||||
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
|
||||
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -664,6 +664,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||
print_indented!(self, "kind: PatKind {", depth_lvl);
|
||||
|
||||
match pat_kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => {
|
||||
print_indented!(self, "Wild", depth_lvl + 1);
|
||||
}
|
||||
@ -740,10 +741,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
|
||||
PatKind::ExpandedConstant { def_id, subpattern } => {
|
||||
print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
|
||||
print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
|
||||
print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
|
||||
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
|
@ -2987,9 +2987,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
match ty {
|
||||
Ok(ty) => {
|
||||
let ident = Ident::new(kw::Empty, this.prev_token.span);
|
||||
let bm = BindingMode::NONE;
|
||||
let pat = this.mk_pat_ident(ty.span, bm, ident);
|
||||
let pat = this.mk_pat(ty.span, PatKind::Missing);
|
||||
(pat, ty)
|
||||
}
|
||||
// If this is a C-variadic argument and we hit an error, return the error.
|
||||
|
@ -75,10 +75,11 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) {
|
||||
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
|
||||
let super_span = this.token.span;
|
||||
this.expect_keyword(exp!(Super))?;
|
||||
this.psess.gated_spans.gate(sym::super_let, this.prev_token.span);
|
||||
this.expect_keyword(exp!(Let))?;
|
||||
let local = this.parse_local(attrs)?; // FIXME(mara): implement super let
|
||||
this.psess.gated_spans.gate(sym::super_let, super_span);
|
||||
let local = this.parse_local(Some(super_span), attrs)?;
|
||||
let trailing = Trailing::from(capture_semi && this.token == token::Semi);
|
||||
Ok((
|
||||
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
|
||||
@ -89,7 +90,7 @@ impl<'a> Parser<'a> {
|
||||
} else if self.token.is_keyword(kw::Let) {
|
||||
self.collect_tokens(None, attrs, force_collect, |this, attrs| {
|
||||
this.expect_keyword(exp!(Let))?;
|
||||
let local = this.parse_local(attrs)?;
|
||||
let local = this.parse_local(None, attrs)?;
|
||||
let trailing = Trailing::from(capture_semi && this.token == token::Semi);
|
||||
Ok((
|
||||
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
|
||||
@ -294,7 +295,7 @@ impl<'a> Parser<'a> {
|
||||
force_collect: ForceCollect,
|
||||
) -> PResult<'a, Stmt> {
|
||||
let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| {
|
||||
let local = this.parse_local(attrs)?;
|
||||
let local = this.parse_local(None, attrs)?;
|
||||
// FIXME - maybe capture semicolon in recovery?
|
||||
Ok((
|
||||
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
|
||||
@ -308,8 +309,8 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parses a local variable declaration.
|
||||
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
||||
let lo = self.prev_token.span;
|
||||
fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, P<Local>> {
|
||||
let lo = super_.unwrap_or(self.prev_token.span);
|
||||
|
||||
if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
|
||||
self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
|
||||
@ -411,6 +412,7 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
|
||||
Ok(P(ast::Local {
|
||||
super_,
|
||||
ty,
|
||||
pat,
|
||||
kind,
|
||||
|
@ -1598,7 +1598,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
if target == Target::ForeignMod
|
||||
&& let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
|
||||
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
|
||||
&& !matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic)
|
||||
&& !matches!(abi, ExternAbi::Rust)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -295,6 +295,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||
record_variants!(
|
||||
(self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
|
||||
[
|
||||
Missing,
|
||||
Wild,
|
||||
Binding,
|
||||
Struct,
|
||||
@ -597,6 +598,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
||||
record_variants!(
|
||||
(self, p, p.kind, None, ast, Pat, PatKind),
|
||||
[
|
||||
Missing,
|
||||
Wild,
|
||||
Ident,
|
||||
Struct,
|
||||
|
@ -96,7 +96,7 @@ use rustc_middle::query::Providers;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{BytePos, Span, Symbol, kw, sym};
|
||||
use rustc_span::{BytePos, Span, Symbol, sym};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use self::LiveNodeKind::*;
|
||||
@ -1481,9 +1481,6 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||
|
||||
fn should_warn(&self, var: Variable) -> Option<String> {
|
||||
let name = self.ir.variable_name(var);
|
||||
if name == kw::Empty {
|
||||
return None;
|
||||
}
|
||||
let name = name.as_str();
|
||||
if name.as_bytes()[0] == b'_' {
|
||||
return None;
|
||||
|
@ -460,7 +460,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
||||
PatKind::AscribeUserType { subpattern, .. }
|
||||
| PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
|
||||
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
|
||||
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
|
||||
PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
|
||||
ctor = Wildcard;
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
|
@ -4009,22 +4009,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
||||
self.report_error(ident.span, error(ident));
|
||||
}
|
||||
|
||||
// Record as bound if it's valid:
|
||||
let ident_valid = ident.name != kw::Empty;
|
||||
if ident_valid {
|
||||
bindings.last_mut().unwrap().1.insert(ident);
|
||||
}
|
||||
// Record as bound.
|
||||
bindings.last_mut().unwrap().1.insert(ident);
|
||||
|
||||
if already_bound_or {
|
||||
// `Variant1(a) | Variant2(a)`, ok
|
||||
// Reuse definition from the first `a`.
|
||||
self.innermost_rib_bindings(ValueNS)[&ident]
|
||||
} else {
|
||||
// A completely fresh binding is added to the set.
|
||||
let res = Res::Local(pat_id);
|
||||
if ident_valid {
|
||||
// A completely fresh binding add to the set if it's valid.
|
||||
self.innermost_rib_bindings(ValueNS).insert(ident, res);
|
||||
}
|
||||
self.innermost_rib_bindings(ValueNS).insert(ident, res);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
@ -491,7 +491,6 @@ impl RustcInternal for Abi {
|
||||
Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall,
|
||||
Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry,
|
||||
Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind },
|
||||
Abi::RustIntrinsic => rustc_abi::ExternAbi::RustIntrinsic,
|
||||
Abi::RustCall => rustc_abi::ExternAbi::RustCall,
|
||||
Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted,
|
||||
Abi::RustCold => rustc_abi::ExternAbi::RustCold,
|
||||
|
@ -871,7 +871,6 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
|
||||
ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
|
||||
ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry,
|
||||
ExternAbi::System { unwind } => Abi::System { unwind },
|
||||
ExternAbi::RustIntrinsic => Abi::RustIntrinsic,
|
||||
ExternAbi::RustCall => Abi::RustCall,
|
||||
ExternAbi::Unadjusted => Abi::Unadjusted,
|
||||
ExternAbi::RustCold => Abi::RustCold,
|
||||
|
@ -1093,7 +1093,6 @@ pub enum Abi {
|
||||
CCmseNonSecureCall,
|
||||
CCmseNonSecureEntry,
|
||||
System { unwind: bool },
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
Unadjusted,
|
||||
RustCold,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_abi::{
|
||||
BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
|
||||
TyAbiInterface, TyAndLayout, Variants,
|
||||
BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
|
||||
TyAndLayout, Variants,
|
||||
};
|
||||
|
||||
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
|
||||
@ -364,15 +364,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if abi == ExternAbi::RustIntrinsic {
|
||||
return;
|
||||
}
|
||||
|
||||
let grlen = cx.data_layout().pointer_size.bits();
|
||||
|
||||
for arg in fn_abi.args.iter_mut() {
|
||||
|
@ -717,16 +717,16 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: ExternAbi)
|
||||
pub fn adjust_for_rust_abi<C>(&mut self, cx: &C)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
let spec = cx.target_spec();
|
||||
match &*spec.arch {
|
||||
"x86" => x86::compute_rust_abi_info(cx, self, abi),
|
||||
"riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
|
||||
"loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
|
||||
"x86" => x86::compute_rust_abi_info(cx, self),
|
||||
"riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self),
|
||||
"loongarch64" => loongarch::compute_rust_abi_info(cx, self),
|
||||
"aarch64" => aarch64::compute_rust_abi_info(cx, self),
|
||||
_ => {}
|
||||
};
|
||||
@ -850,10 +850,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
|
||||
//
|
||||
// Note that the intrinsic ABI is exempt here as those are not
|
||||
// real functions anyway, and the backend expects very specific types.
|
||||
if abi != ExternAbi::RustIntrinsic
|
||||
&& spec.simd_types_indirect
|
||||
&& !can_pass_simd_directly(arg)
|
||||
{
|
||||
if spec.simd_types_indirect && !can_pass_simd_directly(arg) {
|
||||
arg.make_indirect();
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
|
||||
|
||||
use rustc_abi::{
|
||||
BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
|
||||
TyAbiInterface, TyAndLayout, Variants,
|
||||
BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
|
||||
TyAndLayout, Variants,
|
||||
};
|
||||
|
||||
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
|
||||
@ -370,15 +370,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
{
|
||||
if abi == ExternAbi::RustIntrinsic {
|
||||
return;
|
||||
}
|
||||
|
||||
let xlen = cx.data_layout().pointer_size.bits();
|
||||
|
||||
for arg in fn_abi.args.iter_mut() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use rustc_abi::{
|
||||
AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind,
|
||||
TyAbiInterface, TyAndLayout,
|
||||
AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAbiInterface,
|
||||
TyAndLayout,
|
||||
};
|
||||
|
||||
use crate::callconv::{ArgAttribute, FnAbi, PassMode};
|
||||
@ -193,7 +193,7 @@ pub(crate) fn fill_inregs<'a, Ty, C>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
|
||||
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
C: HasDataLayout + HasTargetSpec,
|
||||
@ -201,10 +201,7 @@ where
|
||||
// Avoid returning floats in x87 registers on x86 as loading and storing from x87
|
||||
// registers will quiet signalling NaNs. Also avoid using SSE registers since they
|
||||
// are not always available (depending on target features).
|
||||
if !fn_abi.ret.is_ignore()
|
||||
// Intrinsics themselves are not "real" functions, so theres no need to change their ABIs.
|
||||
&& abi != ExternAbi::RustIntrinsic
|
||||
{
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
let has_float = match fn_abi.ret.layout.backend_repr {
|
||||
BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)),
|
||||
BackendRepr::ScalarPair(s1, s2) => {
|
||||
|
@ -2962,14 +2962,9 @@ impl Target {
|
||||
pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
|
||||
use ExternAbi::*;
|
||||
match abi {
|
||||
Rust
|
||||
| C { .. }
|
||||
| System { .. }
|
||||
| RustIntrinsic
|
||||
| RustCall
|
||||
| Unadjusted
|
||||
| Cdecl { .. }
|
||||
| RustCold => true,
|
||||
Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => {
|
||||
true
|
||||
}
|
||||
EfiApi => {
|
||||
["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ fn fn_sig_for_fn_abi<'tcx>(
|
||||
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv {
|
||||
use rustc_abi::ExternAbi::*;
|
||||
match tcx.sess.target.adjust_abi(abi, c_variadic) {
|
||||
RustIntrinsic | Rust | RustCall => Conv::Rust,
|
||||
Rust | RustCall => Conv::Rust,
|
||||
|
||||
// This is intentionally not using `Conv::Cold`, as that has to preserve
|
||||
// even SIMD registers, which is generally not a good trade-off.
|
||||
@ -660,7 +660,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
||||
let tcx = cx.tcx();
|
||||
|
||||
if abi.is_rustic_abi() {
|
||||
fn_abi.adjust_for_rust_abi(cx, abi);
|
||||
fn_abi.adjust_for_rust_abi(cx);
|
||||
|
||||
// Look up the deduced parameter attributes for this function, if we have its def ID and
|
||||
// we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
|
||||
|
@ -8,6 +8,7 @@
|
||||
//! Note: any changes to the constness of intrinsics should be discussed with the language team.
|
||||
//! This includes changes in the stability of the constness.
|
||||
//!
|
||||
//! //FIXME(#132735) "old" style intrinsics support has been removed
|
||||
//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new"
|
||||
//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the
|
||||
//! implementation from <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to
|
||||
|
@ -52,9 +52,8 @@ with any regular function.
|
||||
Various intrinsics have native MIR operations that they correspond to. Instead of requiring
|
||||
backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
|
||||
will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
|
||||
at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
|
||||
or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
|
||||
anymore after MIR analyses.
|
||||
at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`.
|
||||
The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
|
||||
|
||||
## Intrinsics without fallback logic
|
||||
|
||||
@ -70,28 +69,3 @@ These are written without a body:
|
||||
#[rustc_intrinsic]
|
||||
pub fn abort() -> !;
|
||||
```
|
||||
|
||||
### Legacy extern ABI based intrinsics
|
||||
|
||||
*This style is deprecated, always prefer the above form.*
|
||||
|
||||
These are imported as if they were FFI functions, with the special
|
||||
`rust-intrinsic` ABI. For example, if one was in a freestanding
|
||||
context, but wished to be able to `transmute` between types, and
|
||||
perform efficient pointer arithmetic, one would import those functions
|
||||
via a declaration like
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
# fn main() {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn transmute<T, U>(x: T) -> U;
|
||||
|
||||
fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
}
|
||||
```
|
||||
|
||||
As with any other FFI functions, these are by default always `unsafe` to call.
|
||||
You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
|
||||
|
@ -11,7 +11,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{BodyId, Mutability};
|
||||
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_metadata::rendered_const;
|
||||
use rustc_middle::span_bug;
|
||||
@ -687,8 +686,6 @@ impl Item {
|
||||
hir::FnHeader {
|
||||
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else if abi == ExternAbi::RustIntrinsic {
|
||||
intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
|
||||
} else {
|
||||
safety.into()
|
||||
},
|
||||
|
@ -304,6 +304,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
||||
|
||||
Symbol::intern(&match &p.kind {
|
||||
// FIXME(never_patterns): does this make sense?
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild
|
||||
| PatKind::Err(_)
|
||||
| PatKind::Never
|
||||
|
@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
||||
pats.iter().all(unary_pattern)
|
||||
}
|
||||
match &pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Slice(_, _, _)
|
||||
| PatKind::Range(_, _, _)
|
||||
| PatKind::Binding(..)
|
||||
|
@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>(
|
||||
impl<'a> NormalizedPat<'a> {
|
||||
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
|
||||
PatKind::Binding(.., Some(pat))
|
||||
| PatKind::Box(pat)
|
||||
|
@ -406,6 +406,7 @@ impl<'a> PatState<'a> {
|
||||
pats.iter().map(|p| p.pat),
|
||||
),
|
||||
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild
|
||||
| PatKind::Binding(_, _, _, None)
|
||||
| PatKind::Expr(_)
|
||||
|
@ -224,6 +224,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
|
||||
|
||||
// We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
|
||||
let changed = match &mut focus_kind {
|
||||
Missing => unreachable!(),
|
||||
// These pattern forms are "leafs" and do not have sub-patterns.
|
||||
// Therefore they are not some form of constructor `C`,
|
||||
// with which a pattern `C(p_0)` may be formed,
|
||||
|
@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
}
|
||||
|
||||
match pat.value.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => kind!("Wild"),
|
||||
PatKind::Never => kind!("Never"),
|
||||
PatKind::Binding(ann, _, name, sub) => {
|
||||
|
@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool {
|
||||
pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
||||
use PatKind::*;
|
||||
match (&l.kind, &r.kind) {
|
||||
(Missing, _) | (_, Missing) => unreachable!(),
|
||||
(Paren(l), _) => eq_pat(l, r),
|
||||
(_, Paren(r)) => eq_pat(l, r),
|
||||
(Wild, Wild) | (Rest, Rest) => true,
|
||||
|
@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
|
||||
std::mem::discriminant(&pat.kind).hash(&mut self.s);
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
|
||||
std::mem::discriminant(&by_ref).hash(&mut self.s);
|
||||
std::mem::discriminant(&mutability).hash(&mut self.s);
|
||||
|
@ -1858,6 +1858,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||
}
|
||||
|
||||
match pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
|
||||
PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
|
||||
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
|
||||
|
@ -400,7 +400,6 @@ pub enum FnAbi {
|
||||
Rust,
|
||||
RustCall,
|
||||
RustCold,
|
||||
RustIntrinsic,
|
||||
Stdcall,
|
||||
StdcallUnwind,
|
||||
System,
|
||||
@ -457,7 +456,6 @@ impl FnAbi {
|
||||
s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
|
||||
s if *s == sym::rust_dash_call => FnAbi::RustCall,
|
||||
s if *s == sym::rust_dash_cold => FnAbi::RustCold,
|
||||
s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
|
||||
s if *s == sym::Rust => FnAbi::Rust,
|
||||
s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
|
||||
s if *s == sym::stdcall => FnAbi::Stdcall,
|
||||
@ -500,7 +498,6 @@ impl FnAbi {
|
||||
FnAbi::Rust => "Rust",
|
||||
FnAbi::RustCall => "rust-call",
|
||||
FnAbi::RustCold => "rust-cold",
|
||||
FnAbi::RustIntrinsic => "rust-intrinsic",
|
||||
FnAbi::Stdcall => "stdcall",
|
||||
FnAbi::StdcallUnwind => "stdcall-unwind",
|
||||
FnAbi::System => "system",
|
||||
|
@ -59,19 +59,7 @@ impl Evaluator<'_> {
|
||||
|
||||
let function_data = self.db.function_data(def);
|
||||
let attrs = self.db.attrs(def.into());
|
||||
let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
|
||||
// Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
|
||||
|| (match &function_data.abi {
|
||||
Some(abi) => *abi == sym::rust_dash_intrinsic,
|
||||
None => match def.lookup(self.db.upcast()).container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
let id = block.lookup(self.db.upcast()).id;
|
||||
id.item_tree(self.db.upcast())[id.value].abi.as_ref()
|
||||
== Some(&sym::rust_dash_intrinsic)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
});
|
||||
let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists();
|
||||
|
||||
if is_intrinsic {
|
||||
return self.exec_intrinsic(
|
||||
|
@ -18,7 +18,6 @@ use hir_def::{
|
||||
TypeOrConstParamId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use intern::sym;
|
||||
use rustc_abi::TargetDataLayout;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@ -303,26 +302,13 @@ pub fn is_fn_unsafe_to_call(
|
||||
|
||||
let loc = func.lookup(db.upcast());
|
||||
match loc.container {
|
||||
hir_def::ItemContainerId::ExternBlockId(block) => {
|
||||
let id = block.lookup(db.upcast()).id;
|
||||
let is_intrinsic_block =
|
||||
id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
|
||||
if is_intrinsic_block {
|
||||
// legacy intrinsics
|
||||
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
|
||||
if db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() {
|
||||
Unsafety::Safe
|
||||
} else {
|
||||
Unsafety::Unsafe
|
||||
}
|
||||
hir_def::ItemContainerId::ExternBlockId(_block) => {
|
||||
// Function in an `extern` block are always unsafe to call, except when
|
||||
// it is marked as `safe`.
|
||||
if data.is_safe() {
|
||||
Unsafety::Safe
|
||||
} else {
|
||||
// Function in an `extern` block are always unsafe to call, except when
|
||||
// it is marked as `safe`.
|
||||
if data.is_safe() {
|
||||
Unsafety::Safe
|
||||
} else {
|
||||
Unsafety::Unsafe
|
||||
}
|
||||
Unsafety::Unsafe
|
||||
}
|
||||
}
|
||||
_ => Unsafety::Safe,
|
||||
|
@ -36,7 +36,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
|
||||
"wasm",
|
||||
"system",
|
||||
"system-unwind",
|
||||
"rust-intrinsic",
|
||||
"rust-call",
|
||||
"unadjusted",
|
||||
];
|
||||
|
@ -6945,9 +6945,8 @@ fn hover_feature() {
|
||||
Various intrinsics have native MIR operations that they correspond to. Instead of requiring
|
||||
backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
|
||||
will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
|
||||
at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
|
||||
or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
|
||||
anymore after MIR analyses.
|
||||
at all. These intrinsics only make sense without a body, and can be as a `#[rustc_intrinsic]`.
|
||||
The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
|
||||
|
||||
## Intrinsics without fallback logic
|
||||
|
||||
@ -6960,29 +6959,6 @@ fn hover_feature() {
|
||||
`#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
|
||||
invoke the body.
|
||||
|
||||
### Legacy extern ABI based intrinsics
|
||||
|
||||
These are imported as if they were FFI functions, with the special
|
||||
`rust-intrinsic` ABI. For example, if one was in a freestanding
|
||||
context, but wished to be able to `transmute` between types, and
|
||||
perform efficient pointer arithmetic, one would import those functions
|
||||
via a declaration like
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
# fn main() {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn transmute<T, U>(x: T) -> U;
|
||||
|
||||
fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
}
|
||||
```
|
||||
|
||||
As with any other FFI functions, these are by default always `unsafe` to call.
|
||||
You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
|
||||
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -125,7 +125,6 @@ define_symbols! {
|
||||
riscv_dash_interrupt_dash_s = "riscv-interrupt-s",
|
||||
rust_dash_call = "rust-call",
|
||||
rust_dash_cold = "rust-cold",
|
||||
rust_dash_intrinsic = "rust-intrinsic",
|
||||
stdcall_dash_unwind = "stdcall-unwind",
|
||||
system_dash_unwind = "system-unwind",
|
||||
sysv64_dash_unwind = "sysv64-unwind",
|
||||
|
@ -2442,11 +2442,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param
|
||||
}
|
||||
|
||||
pub(crate) fn is_named_param(param: &ast::Param) -> bool {
|
||||
if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
|
||||
ident.name != symbol::kw::Empty
|
||||
} else {
|
||||
true
|
||||
}
|
||||
!matches!(param.pat.kind, ast::PatKind::Missing)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern(
|
||||
|
||||
fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
|
||||
match &pat.kind {
|
||||
ast::PatKind::Missing => unreachable!(),
|
||||
ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
|
||||
true
|
||||
}
|
||||
@ -100,6 +101,7 @@ impl Rewrite for Pat {
|
||||
|
||||
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
|
||||
match self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Or(ref pats) => {
|
||||
let pat_strs = pats
|
||||
.iter()
|
||||
|
@ -35,9 +35,8 @@ pub struct m64x2([i64; 2]);
|
||||
#[repr(simd)]
|
||||
pub struct m64x4([i64; 4]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_bitmask<V, B>(mask: V) -> B;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_bitmask<V, B>(mask: V) -> B;
|
||||
|
||||
// CHECK-LABEL: bitmask_m8x16
|
||||
#[no_mangle]
|
||||
|
@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
|
||||
#[repr(simd)]
|
||||
pub struct pf64x4([*const f64; 4]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V;
|
||||
|
||||
// CHECK-LABEL: gather_f64x4
|
||||
#[no_mangle]
|
||||
|
@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
|
||||
#[repr(simd)]
|
||||
pub struct m64x4([i64; 4]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
|
||||
|
||||
// CHECK-LABEL: load_i8x16
|
||||
#[no_mangle]
|
||||
|
@ -20,10 +20,10 @@ use minicore::*;
|
||||
#[repr(simd)]
|
||||
pub struct mask8x16([i8; 16]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_reduce_all<T>(x: T) -> bool;
|
||||
fn simd_reduce_any<T>(x: T) -> bool;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_reduce_all<T>(x: T) -> bool;
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_reduce_any<T>(x: T) -> bool;
|
||||
|
||||
// CHECK-LABEL: mask_reduce_all:
|
||||
#[no_mangle]
|
||||
|
@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
|
||||
#[repr(simd)]
|
||||
pub struct m64x4([i64; 4]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
|
||||
|
||||
// CHECK-LABEL: store_i8x16
|
||||
#[no_mangle]
|
||||
|
@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
|
||||
#[repr(simd)]
|
||||
pub struct pf64x4([*mut f64; 4]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M);
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M);
|
||||
|
||||
// CHECK-LABEL: scatter_f64x4
|
||||
#[no_mangle]
|
||||
|
@ -48,9 +48,8 @@ pub struct f64x8([f64; 8]);
|
||||
#[repr(simd)]
|
||||
pub struct m64x8([i64; 8]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_select<M, V>(mask: M, a: V, b: V) -> V;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_select<M, V>(mask: M, a: V, b: V) -> V;
|
||||
|
||||
// CHECK-LABEL: select_i8x16
|
||||
#[no_mangle]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user