1
Fork 0

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:
bors 2025-04-07 12:58:15 +00:00
commit e643f59f6d
166 changed files with 1790 additions and 1636 deletions

View file

@ -60,7 +60,6 @@ pub enum ExternAbi {
System { System {
unwind: bool, unwind: bool,
}, },
RustIntrinsic,
RustCall, RustCall,
/// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even /// *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! /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI!
@ -128,7 +127,6 @@ abi_impls! {
RiscvInterruptS =><= "riscv-interrupt-s", RiscvInterruptS =><= "riscv-interrupt-s",
RustCall =><= "rust-call", RustCall =><= "rust-call",
RustCold =><= "rust-cold", RustCold =><= "rust-cold",
RustIntrinsic =><= "rust-intrinsic",
Stdcall { unwind: false } =><= "stdcall", Stdcall { unwind: false } =><= "stdcall",
Stdcall { unwind: true } =><= "stdcall-unwind", Stdcall { unwind: true } =><= "stdcall-unwind",
System { unwind: false } =><= "system", System { unwind: false } =><= "system",
@ -199,7 +197,7 @@ impl ExternAbi {
/// - are subject to change between compiler versions /// - are subject to change between compiler versions
pub fn is_rustic_abi(self) -> bool { pub fn is_rustic_abi(self) -> bool {
use ExternAbi::*; use ExternAbi::*;
matches!(self, Rust | RustCall | RustIntrinsic | RustCold) matches!(self, Rust | RustCall | RustCold)
} }
pub fn supports_varargs(self) -> bool { pub fn supports_varargs(self) -> bool {

View file

@ -563,6 +563,7 @@ impl Pat {
/// This is intended for use by diagnostics. /// This is intended for use by diagnostics.
pub fn to_ty(&self) -> Option<P<Ty>> { pub fn to_ty(&self) -> Option<P<Ty>> {
let kind = match &self.kind { let kind = match &self.kind {
PatKind::Missing => unreachable!(),
// In a type expression `_` is an inference variable. // In a type expression `_` is an inference variable.
PatKind::Wild => TyKind::Infer, PatKind::Wild => TyKind::Infer,
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. // 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), | PatKind::Guard(s, _) => s.walk(it),
// These patterns do not contain subpatterns, skip. // These patterns do not contain subpatterns, skip.
PatKind::Wild PatKind::Missing
| PatKind::Wild
| PatKind::Rest | PatKind::Rest
| PatKind::Never | PatKind::Never
| PatKind::Expr(_) | PatKind::Expr(_)
@ -676,6 +678,7 @@ impl Pat {
/// Return a name suitable for diagnostics. /// Return a name suitable for diagnostics.
pub fn descr(&self) -> Option<String> { pub fn descr(&self) -> Option<String> {
match &self.kind { match &self.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => Some("_".to_string()), PatKind::Wild => Some("_".to_string()),
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")), PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())), 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`. // Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum PatKind { 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 (`_`). /// Represents a wildcard pattern (`_`).
Wild, Wild,
@ -1169,6 +1175,7 @@ pub enum MacStmtStyle {
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct Local { pub struct Local {
pub id: NodeId, pub id: NodeId,
pub super_: Option<Span>,
pub pat: P<Pat>, pub pat: P<Pat>,
pub ty: Option<P<Ty>>, pub ty: Option<P<Ty>>,
pub kind: LocalKind, pub kind: LocalKind,
@ -3926,7 +3933,7 @@ mod size_asserts {
static_assert_size!(Item, 144); static_assert_size!(Item, 144);
static_assert_size!(ItemKind, 80); static_assert_size!(ItemKind, 80);
static_assert_size!(LitKind, 24); static_assert_size!(LitKind, 24);
static_assert_size!(Local, 80); static_assert_size!(Local, 96);
static_assert_size!(MetaItemLit, 40); static_assert_size!(MetaItemLit, 40);
static_assert_size!(Param, 40); static_assert_size!(Param, 40);
static_assert_size!(Pat, 72); static_assert_size!(Pat, 72);

View file

@ -92,6 +92,12 @@ pub struct AutoDiffAttrs {
pub input_activity: Vec<DiffActivity>, pub input_activity: Vec<DiffActivity>,
} }
impl AutoDiffAttrs {
pub fn has_primal_ret(&self) -> bool {
matches!(self.ret_activity, DiffActivity::Active | DiffActivity::Dual)
}
}
impl DiffMode { impl DiffMode {
pub fn is_rev(&self) -> bool { pub fn is_rev(&self) -> bool {
matches!(self, DiffMode::Reverse) matches!(self, DiffMode::Reverse)

View file

@ -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>) { 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); vis.visit_id(id);
visit_attrs(vis, attrs); visit_attrs(vis, attrs);
vis.visit_pat(pat); 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); vis.visit_id(id);
match kind { match kind {
PatKind::Err(_guar) => {} PatKind::Err(_guar) => {}
PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
PatKind::Ident(_binding_mode, ident, sub) => { PatKind::Ident(_binding_mode, ident, sub) => {
vis.visit_ident(ident); vis.visit_ident(ident);
visit_opt(sub, |sub| vis.visit_pat(sub)); visit_opt(sub, |sub| vis.visit_pat(sub));

View file

@ -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 { 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); walk_list!(visitor, visit_attribute, attrs);
try_visit!(visitor.visit_pat(pat)); try_visit!(visitor.visit_pat(pat));
visit_opt!(visitor, visit_ty, ty); 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_pat(subpattern));
try_visit!(visitor.visit_expr(guard_condition)); 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::Err(_guar) => {}
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
walk_list!(visitor, visit_pat, elems); walk_list!(visitor, visit_pat, elems);

View file

@ -95,6 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> { fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
// Let statements are allowed to have impl trait in bindings. // Let statements are allowed to have impl trait in bindings.
let super_ = l.super_;
let ty = l.ty.as_ref().map(|t| { let ty = l.ty.as_ref().map(|t| {
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable)) 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 span = self.lower_span(l.span);
let source = hir::LocalSource::Normal; let source = hir::LocalSource::Normal;
self.lower_attrs(hir_id, &l.attrs, l.span); 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 { fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {

View file

@ -1496,18 +1496,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] { 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 { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => { PatKind::Missing => None,
if ident.name != kw::Empty { PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)),
Some(self.lower_ident(ident))
} else {
None
}
}
PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))), PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
_ => { _ => {
self.dcx().span_delayed_bug( self.dcx().span_delayed_bug(
param.pat.span, param.pat.span,
"non-ident/wild param pat must trigger an error", "non-missing/ident/wild param pat must trigger an error",
); );
None None
} }
@ -2223,6 +2218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.attrs.insert(hir_id.local_id, a); self.attrs.insert(hir_id.local_id, a);
} }
let local = hir::LetStmt { let local = hir::LetStmt {
super_: None,
hir_id, hir_id,
init, init,
pat, pat,

View file

@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let pat_hir_id = self.lower_node_id(pattern.id); let pat_hir_id = self.lower_node_id(pattern.id);
let node = loop { let node = loop {
match &pattern.kind { match &pattern.kind {
PatKind::Missing => break hir::PatKind::Missing,
PatKind::Wild => break hir::PatKind::Wild, PatKind::Wild => break hir::PatKind::Wild,
PatKind::Never => break hir::PatKind::Never, PatKind::Never => break hir::PatKind::Never,
PatKind::Ident(binding_mode, ident, sub) => { PatKind::Ident(binding_mode, ident, sub) => {

View file

@ -79,10 +79,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
| ExternAbi::SysV64 { .. } | ExternAbi::SysV64 { .. }
| ExternAbi::System { .. } | ExternAbi::System { .. }
| ExternAbi::EfiApi => Ok(()), | ExternAbi::EfiApi => Ok(()),
// implementation details
ExternAbi::RustIntrinsic => {
Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
}
ExternAbi::Unadjusted => { ExternAbi::Unadjusted => {
Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail }) Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
} }

View file

@ -244,7 +244,7 @@ impl<'a> AstValidator<'a> {
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) { fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
for Param { pat, .. } in &decl.inputs { for Param { pat, .. } in &decl.inputs {
match pat.kind { 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) => { PatKind::Ident(BindingMode::MUT, ident, None) => {
report_err(pat.span, Some(ident), true) report_err(pat.span, Some(ident), true)
} }

View file

@ -1336,6 +1336,9 @@ impl<'a> State<'a> {
self.print_outer_attributes(&loc.attrs); self.print_outer_attributes(&loc.attrs);
self.space_if_not_bol(); self.space_if_not_bol();
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
if loc.super_.is_some() {
self.word_nbsp("super");
}
self.word_nbsp("let"); self.word_nbsp("let");
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
@ -1622,9 +1625,9 @@ impl<'a> State<'a> {
fn print_pat(&mut self, pat: &ast::Pat) { fn print_pat(&mut self, pat: &ast::Pat) {
self.maybe_print_comment(pat.span.lo()); self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat)); self.ann.pre(self, AnnNode::Pat(pat));
/* Pat isn't normalized, but the beauty of it /* Pat isn't normalized, but the beauty of it is that it doesn't matter */
is that it doesn't matter */
match &pat.kind { match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => self.word("_"), PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"), PatKind::Never => self.word("!"),
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => { PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
@ -1946,12 +1949,7 @@ impl<'a> State<'a> {
if let Some(eself) = input.to_self() { if let Some(eself) = input.to_self() {
self.print_explicit_self(&eself); self.print_explicit_self(&eself);
} else { } else {
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind { if !matches!(input.pat.kind, PatKind::Missing) {
ident.name == kw::Empty
} else {
false
};
if !invalid {
self.print_pat(&input.pat); self.print_pat(&input.pat);
self.word(":"); self.word(":");
self.space(); self.space();

View file

@ -22,7 +22,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_span::hygiene::DesugaringKind; use rustc_span::hygiene::DesugaringKind;
use rustc_span::{DUMMY_SP, Span}; use rustc_span::{DUMMY_SP, Span};
use tracing::{debug, instrument, trace}; use tracing::{Level, debug, enabled, instrument, trace};
use crate::BorrowckInferCtxt; use crate::BorrowckInferCtxt;
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph}; 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<_>>(); let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
var_to_origin_sorted.sort_by_key(|vto| vto.0); var_to_origin_sorted.sort_by_key(|vto| vto.0);
if enabled!(Level::DEBUG) {
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string(); 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() { for (reg_var, origin) in var_to_origin_sorted.into_iter() {
reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n")); 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 num_components = sccs.num_sccs();
let mut components = vec![FxIndexSet::default(); num_components]; let mut components = vec![FxIndexSet::default(); num_components];
@ -342,6 +344,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
components[scc_idx.as_usize()].insert((reg_var, *origin)); components[scc_idx.as_usize()].insert((reg_var, *origin));
} }
if enabled!(Level::DEBUG) {
let mut components_str = "strongly connected components:".to_string(); let mut components_str = "strongly connected components:".to_string();
for (scc_idx, reg_vars_origins) in components.iter().enumerate() { for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>(); let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
@ -352,6 +355,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
)) ))
} }
debug!("{}", components_str); debug!("{}", components_str);
}
// calculate the best representative for each component // calculate the best representative for each component
let components_representatives = components let components_representatives = components

View file

@ -1,5 +1,4 @@
//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, //! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute
//! functions marked with the `#[rustc_intrinsic]` attribute
//! and LLVM intrinsics that have symbol names starting with `llvm.`. //! and LLVM intrinsics that have symbol names starting with `llvm.`.
macro_rules! intrinsic_args { macro_rules! intrinsic_args {

View file

@ -201,7 +201,23 @@ fn compute_enzyme_fn_ty<'ll>(
} }
if attrs.width == 1 { 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 { } else {
// First we check if we also have to deal with the primal return. // First we check if we also have to deal with the primal return.
match attrs.mode { match attrs.mode {
@ -388,7 +404,11 @@ fn generate_enzyme_call<'ll>(
// now store the result of the enzyme call into the sret pointer. // now store the result of the enzyme call into the sret pointer.
let sret_ptr = outer_args[0]; let sret_ptr = outer_args[0];
let call_ty = cx.val_ty(call); let call_ty = cx.val_ty(call);
if attrs.width == 1 {
assert_eq!(cx.type_kind(call_ty), TypeKind::Struct);
} else {
assert_eq!(cx.type_kind(call_ty), TypeKind::Array); assert_eq!(cx.type_kind(call_ty), TypeKind::Array);
}
llvm::LLVMBuildStore(&builder.llbuilder, call, sret_ptr); llvm::LLVMBuildStore(&builder.llbuilder, call, sret_ptr);
} }
builder.ret_void(); builder.ret_void();

View file

@ -53,13 +53,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
None => return, 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 let mut covfun_records = instances_used
.iter() .iter()
.copied() .copied()
@ -67,17 +60,13 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
// order that doesn't depend on the stable-hash-based order in which // order that doesn't depend on the stable-hash-based order in which
// instances were visited during codegen. // instances were visited during codegen.
.sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name) .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<_>>(); .collect::<Vec<_>>();
// In a single designated CGU, also prepare covfun records for functions // In a single designated CGU, also prepare covfun records for functions
// in this crate that were instrumented for coverage, but are unused. // in this crate that were instrumented for coverage, but are unused.
if cx.codegen_unit.is_code_coverage_dead_code_cgu() { if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
unused::prepare_covfun_records_for_unused_functions( unused::prepare_covfun_records_for_unused_functions(cx, &mut covfun_records);
cx,
&mut global_file_table,
&mut covfun_records,
);
} }
// If there are no covfun records for this CGU, don't generate a covmap record. // 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; return;
} }
// Encode all filenames referenced by coverage mappings in this CGU. // Prepare the global file table for this CGU, containing all paths needed
let filenames_buffer = global_file_table.make_filenames_buffer(tcx); // by one or more covfun records.
// The `llvm-cov` tool uses this hash to associate each covfun record with let global_file_table =
// its corresponding filenames table, since the final binary will typically GlobalFileTable::build(tcx, covfun_records.iter().flat_map(|c| c.all_source_files()));
// contain multiple covmap records from different compilation units.
let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
for covfun in &covfun_records { 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 // 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 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.) // (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 { struct GlobalFileTable {
/// This "raw" table doesn't include the working dir, so a file's /// This "raw" table doesn't include the working dir, so a file's
/// global ID is its index in this set **plus one**. /// 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 { impl GlobalFileTable {
fn new() -> Self { /// Builds a "global file table" for this CGU, mapping numeric IDs to
Self { raw_file_table: FxIndexMap::default() } /// path strings.
fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator<Item = &'a SourceFile>) -> Self {
let mut raw_file_table = FxIndexMap::default();
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()
});
} }
fn global_file_id_for_file(&mut self, file: &Arc<SourceFile>) -> GlobalFileId { // FIXME(Zalathar): Consider sorting the file table here, but maybe
// Ensure the given file has a table entry, and get its index. // only after adding filename support to coverage-dump, so that the
let entry = self.raw_file_table.entry(file.stable_id); // table order isn't directly visible in `.coverage-map` snapshots.
let raw_id = entry.index();
entry.or_insert_with(|| Arc::clone(file));
// The raw file table doesn't include an entry for the working dir let mut table = Vec::with_capacity(raw_file_table.len() + 1);
// (which has ID 0), so add 1 to get the correct ID.
GlobalFileId::from_usize(raw_id + 1)
}
fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> { // Since version 6 of the LLVM coverage mapping format, the first entry
let mut table = Vec::with_capacity(self.raw_file_table.len() + 1); // in the global file table is treated as a base directory, used to
// resolve any other entries that are stored as relative paths.
// LLVM Coverage Mapping Format version 6 (zero-based encoded as 5) let base_dir = tcx
// requires setting the first filename to the compilation directory. .sess
// 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 .opts
.working_dir .working_dir
.for_scope(tcx.sess, RemapPathScopeComponents::MACRO) .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
.to_string_lossy(), .to_string_lossy();
); table.push(base_dir.as_ref());
// Add the regular entries after the base directory. // Add the regular entries after the base directory.
table.extend(self.raw_file_table.values().map(|file| { table.extend(raw_file_table.values().map(|name| name.as_str()));
file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
}));
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 {} struct LocalFileId {}
} }
/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU) /// Holds a mapping from "local" (per-function) file IDs to their corresponding
/// file IDs. /// source files.
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct VirtualFileMapping { struct VirtualFileMapping {
local_to_global: IndexVec<LocalFileId, GlobalFileId>, local_file_table: IndexVec<LocalFileId, Arc<SourceFile>>,
global_to_local: FxIndexMap<GlobalFileId, LocalFileId>,
} }
impl VirtualFileMapping { impl VirtualFileMapping {
fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId { fn push_file(&mut self, source_file: &Arc<SourceFile>) -> LocalFileId {
*self self.local_file_table.push(Arc::clone(source_file))
.global_to_local
.entry(global_file_id)
.or_insert_with(|| self.local_to_global.push(global_file_id))
} }
fn to_vec(&self) -> Vec<u32> { /// Resolves all of the filenames in this local file mapping to a list of
// This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`, /// global file IDs in its CGU, for inclusion in this function's
// but it isn't hot or expensive enough to justify the extra unsafety. /// `__llvm_covfun` record.
self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect() ///
/// 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<_>>>()
} }
} }

View file

@ -5,6 +5,7 @@
//! [^win]: On Windows the section name is `.lcovfun`. //! [^win]: On Windows the section name is `.lcovfun`.
use std::ffi::CString; use std::ffi::CString;
use std::sync::Arc;
use rustc_abi::Align; use rustc_abi::Align;
use rustc_codegen_ssa::traits::{ use rustc_codegen_ssa::traits::{
@ -15,7 +16,7 @@ use rustc_middle::mir::coverage::{
MappingKind, Op, MappingKind, Op,
}; };
use rustc_middle::ty::{Instance, TyCtxt}; use rustc_middle::ty::{Instance, TyCtxt};
use rustc_span::Span; use rustc_span::{SourceFile, Span};
use rustc_target::spec::HasTargetSpec; use rustc_target::spec::HasTargetSpec;
use tracing::debug; use tracing::debug;
@ -37,9 +38,16 @@ pub(crate) struct CovfunRecord<'tcx> {
regions: ffi::Regions, 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>( pub(crate) fn prepare_covfun_record<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
global_file_table: &mut GlobalFileTable,
instance: Instance<'tcx>, instance: Instance<'tcx>,
is_used: bool, is_used: bool,
) -> Option<CovfunRecord<'tcx>> { ) -> Option<CovfunRecord<'tcx>> {
@ -57,7 +65,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
regions: ffi::Regions::default(), 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() { if covfun.regions.has_no_regions() {
debug!(?covfun, "function has no mappings to embed; skipping"); 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. /// Populates the mapping region tables in the current function's covfun record.
fn fill_region_tables<'tcx>( fn fill_region_tables<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
global_file_table: &mut GlobalFileTable,
fn_cov_info: &'tcx FunctionCoverageInfo, fn_cov_info: &'tcx FunctionCoverageInfo,
ids_info: &'tcx CoverageIdsInfo, ids_info: &'tcx CoverageIdsInfo,
covfun: &mut CovfunRecord<'tcx>, covfun: &mut CovfunRecord<'tcx>,
@ -106,11 +113,7 @@ fn fill_region_tables<'tcx>(
}; };
let source_file = source_map.lookup_source_file(first_span.lo()); let source_file = source_map.lookup_source_file(first_span.lo());
// Look up the global file ID for that file. let local_file_id = covfun.virtual_file_mapping.push_file(&source_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);
// In rare cases, _all_ of a function's spans are discarded, and coverage // In rare cases, _all_ of a function's spans are discarded, and coverage
// codegen needs to handle that gracefully to avoid #133606. // 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. /// as a global variable in the `__llvm_covfun` section.
pub(crate) fn generate_covfun_record<'tcx>( pub(crate) fn generate_covfun_record<'tcx>(
cx: &CodegenCx<'_, 'tcx>, cx: &CodegenCx<'_, 'tcx>,
filenames_hash: u64, global_file_table: &GlobalFileTable,
covfun: &CovfunRecord<'tcx>, covfun: &CovfunRecord<'tcx>,
) { ) {
let &CovfunRecord { let &CovfunRecord {
@ -191,12 +194,19 @@ pub(crate) fn generate_covfun_record<'tcx>(
ref regions, ref regions,
} = covfun; } = covfun;
// Encode the function's coverage mappings into a buffer. let Some(local_file_table) = virtual_file_mapping.resolve_all(global_file_table) else {
let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer( debug_assert!(
&virtual_file_mapping.to_vec(), false,
expressions, "all local files should be present in the global file table: \
regions, 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(&local_file_table, expressions, regions);
// A covfun record consists of four target-endian integers, followed by the // 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. // 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_u64(func_name_hash),
cx.const_u32(coverage_mapping_buffer.len() as u32), cx.const_u32(coverage_mapping_buffer.len() as u32),
cx.const_u64(source_hash), cx.const_u64(source_hash),
cx.const_u64(filenames_hash), cx.const_u64(global_file_table.filenames_hash),
cx.const_bytes(&coverage_mapping_buffer), cx.const_bytes(&coverage_mapping_buffer),
], ],
// This struct needs to be packed, so that the 32-bit length field // This struct needs to be packed, so that the 32-bit length field

View file

@ -7,7 +7,6 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefIdSet; use rustc_span::def_id::DefIdSet;
use crate::common::CodegenCx; use crate::common::CodegenCx;
use crate::coverageinfo::mapgen::GlobalFileTable;
use crate::coverageinfo::mapgen::covfun::{CovfunRecord, prepare_covfun_record}; use crate::coverageinfo::mapgen::covfun::{CovfunRecord, prepare_covfun_record};
use crate::llvm; use crate::llvm;
@ -21,7 +20,6 @@ use crate::llvm;
/// its embedded coverage data. /// its embedded coverage data.
pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>( pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>(
cx: &CodegenCx<'_, 'tcx>, cx: &CodegenCx<'_, 'tcx>,
global_file_table: &mut GlobalFileTable,
covfun_records: &mut Vec<CovfunRecord<'tcx>>, covfun_records: &mut Vec<CovfunRecord<'tcx>>,
) { ) {
assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu()); 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. // Try to create a covfun record for each unused function.
let mut name_globals = Vec::with_capacity(unused_instances.len()); let mut name_globals = Vec::with_capacity(unused_instances.len());
covfun_records.extend(unused_instances.into_iter().filter_map(|unused| try { 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. // If successful, also store its symbol name in a global constant.
name_globals.push(cx.const_str(unused.symbol_name.name).0); name_globals.push(cx.const_str(unused.symbol_name.name).0);
record record

View file

@ -6,8 +6,9 @@ Erroneous code example:
#![feature(intrinsics)] #![feature(intrinsics)]
#![allow(internal_features)] #![allow(internal_features)]
extern "rust-intrinsic" { extern "C" {
pub static atomic_singlethreadfence_seqcst: fn(); #[rustc_intrinsic]
pub static atomic_singlethreadfence_seqcst: unsafe fn();
// error: intrinsic must be a function // error: intrinsic must be a function
} }
@ -22,9 +23,8 @@ error, just declare a function. Example:
#![feature(intrinsics)] #![feature(intrinsics)]
#![allow(internal_features)] #![allow(internal_features)]
extern "rust-intrinsic" { #[rustc_intrinsic]
pub fn atomic_singlethreadfence_seqcst(); // ok! pub unsafe fn atomic_singlethreadfence_seqcst(); // ok!
}
fn main() { unsafe { atomic_singlethreadfence_seqcst(); } } fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
``` ```

View file

@ -230,6 +230,7 @@ impl<'a> ExtCtxt<'a> {
self.pat_ident(sp, ident) self.pat_ident(sp, ident)
}; };
let local = P(ast::Local { let local = P(ast::Local {
super_: None,
pat, pat,
ty, ty,
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,
@ -245,6 +246,7 @@ impl<'a> ExtCtxt<'a> {
/// Generates `let _: Type;`, which is usually used for type assertions. /// 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 { pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
let local = P(ast::Local { let local = P(ast::Local {
super_: None,
pat: self.pat_wild(span), pat: self.pat_wild(span),
ty: Some(ty), ty: Some(ty),
id: ast::DUMMY_NODE_ID, id: ast::DUMMY_NODE_ID,

View file

@ -211,7 +211,7 @@ declare_features! (
(internal, custom_mir, "1.65.0", None), (internal, custom_mir, "1.65.0", None),
/// Outputs useful `assert!` messages /// Outputs useful `assert!` messages
(unstable, generic_assert, "1.63.0", None), (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), (internal, intrinsics, "1.0.0", None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
(internal, lang_items, "1.0.0", None), (internal, lang_items, "1.0.0", None),
@ -630,7 +630,7 @@ declare_features! (
/// Allows string patterns to dereference values to match them. /// Allows string patterns to dereference values to match them.
(unstable, string_deref_patterns, "1.67.0", Some(87121)), (unstable, string_deref_patterns, "1.67.0", Some(87121)),
/// Allows `super let` statements. /// 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. /// Allows subtrait items to shadow supertrait items.
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
/// Allows using `#[thread_local]` on `static` items. /// Allows using `#[thread_local]` on `static` items.

View file

@ -1555,6 +1555,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*; use PatKind::*;
match self.kind { match self.kind {
Missing => unreachable!(),
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true, Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it), 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)), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
@ -1582,7 +1583,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*; use PatKind::*;
match self.kind { 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), 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)), 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)), 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)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatKind<'hir> { 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., `_`). /// Represents a wildcard pattern (i.e., `_`).
Wild, Wild,
@ -1817,6 +1821,8 @@ pub enum StmtKind<'hir> {
/// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`). /// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
#[derive(Debug, Clone, Copy, HashStable_Generic)] #[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct LetStmt<'hir> { pub struct LetStmt<'hir> {
/// Span of `super` in `super let`.
pub super_: Option<Span>,
pub pat: &'hir Pat<'hir>, pub pat: &'hir Pat<'hir>,
/// Type annotation, if any (otherwise the type will be inferred). /// Type annotation, if any (otherwise the type will be inferred).
pub ty: Option<&'hir Ty<'hir>>, pub ty: Option<&'hir Ty<'hir>>,
@ -4850,7 +4856,7 @@ mod size_asserts {
static_assert_size!(ImplItemKind<'_>, 40); static_assert_size!(ImplItemKind<'_>, 40);
static_assert_size!(Item<'_>, 88); static_assert_size!(Item<'_>, 88);
static_assert_size!(ItemKind<'_>, 64); static_assert_size!(ItemKind<'_>, 64);
static_assert_size!(LetStmt<'_>, 64); static_assert_size!(LetStmt<'_>, 72);
static_assert_size!(Param<'_>, 32); static_assert_size!(Param<'_>, 32);
static_assert_size!(Pat<'_>, 72); static_assert_size!(Pat<'_>, 72);
static_assert_size!(Path<'_>, 40); static_assert_size!(Path<'_>, 40);

View file

@ -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, lower_bound);
visit_opt!(visitor, visit_pat_expr, upper_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) => { PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, prepatterns);
visit_opt!(visitor, visit_pat, slice_pattern); visit_opt!(visitor, visit_pat, slice_pattern);

View file

@ -741,10 +741,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for &assoc_item in assoc_items.in_definition_order() { for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind { 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() => { ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
let trait_args = GenericArgs::identity_for_item(tcx, def_id); let trait_args = GenericArgs::identity_for_item(tcx, def_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
@ -788,9 +784,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
}; };
check_abi(tcx, it.span, abi); check_abi(tcx, it.span, abi);
match abi {
ExternAbi::RustIntrinsic => {
for item in items { 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( intrinsic::check_intrinsic_type(
tcx, tcx,
item.id.owner_id.def_id, item.id.owner_id.def_id,
@ -799,16 +796,11 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
abi, abi,
); );
} }
}
_ => {
for item in items {
let def_id = item.id.owner_id.def_id;
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts(); let own_counts = generics.own_counts();
if generics.own_params.len() - own_counts.lifetimes != 0 { if generics.own_params.len() - own_counts.lifetimes != 0 {
let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
{
(_, 0) => ("type", "types", Some("u32")), (_, 0) => ("type", "types", Some("u32")),
// We don't specify an example value, because we can't generate // We don't specify an example value, because we can't generate
// a valid value for any type. // a valid value for any type.
@ -848,8 +840,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
} }
} }
} }
}
}
_ => {} _ => {}
} }
} }

View file

@ -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_abi::ExternAbi;
use rustc_errors::codes::*; use rustc_errors::codes::*;

View file

@ -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) { pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
// Only restricted on wasm target for now // Only restricted on wasm target for now
if !tcx.sess.target.is_like_wasm { if !tcx.sess.target.is_like_wasm {

View file

@ -8,6 +8,7 @@
use std::mem; use std::mem;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> {
scope_tree: ScopeTree, scope_tree: ScopeTree,
cx: Context, cx: Context,
extended_super_lets: FxHashMap<hir::ItemLocalId, Option<Scope>>,
} }
/// Records the lifetime of a local variable as `cx.var_parent` /// Records the lifetime of a local variable as `cx.var_parent`
@ -214,6 +217,16 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi
let stmt_id = stmt.hir_id.local_id; let stmt_id = stmt.hir_id.local_id;
debug!("resolve_stmt(stmt.id={:?})", stmt_id); debug!("resolve_stmt(stmt.id={:?})", stmt_id);
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 // Every statement will clean up the temporaries created during
// execution of that statement. Therefore each statement has an // execution of that statement. Therefore each statement has an
// associated destruction scope that represents the scope of the // associated destruction scope that represents the scope of the
@ -227,6 +240,7 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi
visitor.cx.parent = prev_parent; visitor.cx.parent = prev_parent;
} }
}
fn resolve_expr<'tcx>( fn resolve_expr<'tcx>(
visitor: &mut ScopeResolutionVisitor<'tcx>, visitor: &mut ScopeResolutionVisitor<'tcx>,
@ -478,14 +492,19 @@ fn resolve_expr<'tcx>(
visitor.cx = prev_cx; visitor.cx = prev_cx;
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum LetKind {
Regular,
Super,
}
fn resolve_local<'tcx>( fn resolve_local<'tcx>(
visitor: &mut ScopeResolutionVisitor<'tcx>, visitor: &mut ScopeResolutionVisitor<'tcx>,
pat: Option<&'tcx hir::Pat<'tcx>>, pat: Option<&'tcx hir::Pat<'tcx>>,
init: Option<&'tcx hir::Expr<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>,
let_kind: LetKind,
) { ) {
debug!("resolve_local(pat={:?}, init={:?})", pat, init); debug!("resolve_local(pat={:?}, init={:?}, let_kind={:?})", pat, init, let_kind);
let blk_scope = visitor.cx.var_parent;
// As an exception to the normal rules governing temporary // As an exception to the normal rules governing temporary
// lifetimes, initializers in a let have a temporary lifetime // 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 // A, but the inner rvalues `a()` and `b()` have an extended lifetime
// due to rule C. // 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 { 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 let Some(pat) = pat {
if is_binding_pat(pat) { if is_binding_pat(pat) {
visitor.scope_tree.record_rvalue_candidate( visitor.scope_tree.record_rvalue_candidate(
expr.hir_id, 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 { if let Some(expr) = init {
visitor.visit_expr(expr); visitor.visit_expr(expr);
} }
if let Some(pat) = pat { if let Some(pat) = pat {
visitor.visit_pat(pat); visitor.visit_pat(pat);
} }
@ -623,6 +679,7 @@ fn resolve_local<'tcx>(
PatKind::Ref(_, _) PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..) | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
| PatKind::Missing
| PatKind::Wild | PatKind::Wild
| PatKind::Never | PatKind::Never
| PatKind::Expr(_) | PatKind::Expr(_)
@ -639,6 +696,7 @@ fn resolve_local<'tcx>(
/// | [ ..., E&, ... ] /// | [ ..., E&, ... ]
/// | ( ..., E&, ... ) /// | ( ..., E&, ... )
/// | {...; E&} /// | {...; E&}
/// | { super let ... = E&; ... }
/// | if _ { ...; E& } else { ...; E& } /// | if _ { ...; E& } else { ...; E& }
/// | match _ { ..., _ => E&, ... } /// | match _ { ..., _ => E&, ... }
/// | box E& /// | box E&
@ -675,6 +733,13 @@ fn resolve_local<'tcx>(
if let Some(subexpr) = block.expr { if let Some(subexpr) = block.expr {
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id); 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) => { hir::ExprKind::If(_, then_block, else_block) => {
record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id); 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, local_id: body.value.hir_id.local_id,
data: ScopeData::Destruction, 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); resolve_expr(self, ex, false);
} }
fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) { 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) { fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
let body = self.tcx.hir_body(c.body); 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 }, cx: Context { parent: None, var_parent: None },
pessimistic_yield: false, pessimistic_yield: false,
fixup_scopes: vec![], fixup_scopes: vec![],
extended_super_lets: Default::default(),
}; };
visitor.scope_tree.root_body = Some(body.value.hir_id); visitor.scope_tree.root_body = Some(body.value.hir_id);

View file

@ -42,7 +42,6 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors; use crate::errors;
use crate::hir_ty_lowering::errors::assoc_kind_str; use crate::hir_ty_lowering::errors::assoc_kind_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
@ -1704,18 +1703,13 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
abi: ExternAbi, abi: ExternAbi,
safety: hir::Safety, safety: hir::Safety,
) -> ty::PolyFnSig<'tcx> { ) -> 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 hir_id = tcx.local_def_id_to_hir_id(def_id);
let fty = let fty =
ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None); 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 // Feature gate SIMD types in FFI, since I am not sure that the
// ABIs are handled at all correctly. -huonw // 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<'_>| { let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
if ty.is_simd() { if ty.is_simd() {
let snip = tcx let snip = tcx

View file

@ -172,34 +172,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}; };
if let Node::TraitItem(item) = node { 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 mut bounds = Vec::new();
let self_ty_where_predicates = (parent, item.generics.predicates); icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
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); predicates.extend(bounds);
} }
}
let generics = tcx.generics_of(def_id); let generics = tcx.generics_of(def_id);

View file

@ -43,12 +43,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} }
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds /// 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 /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
/// should be added everywhere, including super bounds. However this causes a huge performance /// should be added everywhere, including super bounds. However this causes a huge performance
/// costs. For optimization purposes instead of adding default supertraits, bounds /// costs. For optimization purposes instead of adding default supertraits, bounds
/// are added to the associative items: /// are added to the associated items:
/// ///
/// ```ignore(illustrative) /// ```ignore(illustrative)
/// // Default bounds are generated in the following way: /// // 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 /// Therefore, `experimental_default_bounds` are still being added to supertraits if
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
pub(crate) fn requires_default_supertraits( fn requires_default_supertraits(
&self, &self,
hir_bounds: &'tcx [hir::GenericBound<'tcx>], hir_bounds: &'tcx [hir::GenericBound<'tcx>],
hir_generics: &'tcx hir::Generics<'tcx>, hir_generics: &'tcx hir::Generics<'tcx>,
@ -120,6 +120,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
found 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. /// Lazily sets `experimental_default_bounds` to true on trait super bounds.
/// See `requires_default_supertraits` for more information. /// See `requires_default_supertraits` for more information.
pub(crate) fn add_default_super_traits( pub(crate) fn add_default_super_traits(
@ -130,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_generics: &'tcx hir::Generics<'tcx>, hir_generics: &'tcx hir::Generics<'tcx>,
span: Span, 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)); assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
if self.requires_default_supertraits(hir_bounds, hir_generics) { if self.requires_default_supertraits(hir_bounds, hir_generics) {
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
@ -263,8 +304,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
seen_unbound = true; seen_unbound = true;
} }
let emit_relax_err = || { let emit_relax_err = || {
let unbound_traits = let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
match self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
true => "`?Sized` and `experimental_default_bounds`", true => "`?Sized` and `experimental_default_bounds`",
false => "`?Sized`", false => "`?Sized`",
}; };

View file

@ -960,12 +960,16 @@ impl<'a> State<'a> {
fn print_local( fn print_local(
&mut self, &mut self,
super_: bool,
init: Option<&hir::Expr<'_>>, init: Option<&hir::Expr<'_>>,
els: Option<&hir::Block<'_>>, els: Option<&hir::Block<'_>>,
decl: impl Fn(&mut Self), decl: impl Fn(&mut Self),
) { ) {
self.space_if_not_bol(); self.space_if_not_bol();
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
if super_ {
self.word_nbsp("super");
}
self.word_nbsp("let"); self.word_nbsp("let");
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
@ -995,7 +999,9 @@ impl<'a> State<'a> {
self.maybe_print_comment(st.span.lo()); self.maybe_print_comment(st.span.lo());
match st.kind { match st.kind {
hir::StmtKind::Let(loc) => { 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::Item(item) => self.ann.nested(self, Nested::Item(item)),
hir::StmtKind::Expr(expr) => { hir::StmtKind::Expr(expr) => {
@ -1488,7 +1494,7 @@ impl<'a> State<'a> {
// Print `let _t = $init;`: // Print `let _t = $init;`:
let temp = Ident::from_str("_t"); 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(";"); self.word(";");
// Print `_t`: // Print `_t`:
@ -1868,6 +1874,7 @@ impl<'a> State<'a> {
// Pat isn't normalized, but the beauty of it // Pat isn't normalized, but the beauty of it
// is that it doesn't matter // is that it doesn't matter
match pat.kind { match pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => self.word("_"), PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"), PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => { PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {

View file

@ -5,7 +5,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem; 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::infer::RegionVariableOrigin;
use rustc_infer::traits::WellFormedLoc; use rustc_infer::traits::WellFormedLoc;
use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
@ -50,8 +50,6 @@ pub(super) fn check_fn<'a, 'tcx>(
let span = body.value.span; let span = body.value.span;
forbid_intrinsic_abi(tcx, span, fn_sig.abi);
GatherLocalsVisitor::new(fcx).visit_body(body); GatherLocalsVisitor::new(fcx).visit_body(body);
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`

View file

@ -970,7 +970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
// Normalize only after registering in `user_provided_sigs`. // 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 /// Invoked when we are translating the coroutine that results

View file

@ -37,7 +37,6 @@
use std::ops::Deref; use std::ops::Deref;
use rustc_abi::ExternAbi;
use rustc_attr_parsing::InlineAttr; use rustc_attr_parsing::InlineAttr;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, struct_span_code_err}; 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) { 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. // The signature must match.
let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig)); let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
let sig = self let sig = self

View file

@ -482,7 +482,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// All of these constitute a read, or match on something that isn't `!`, // All of these constitute a read, or match on something that isn't `!`,
// which would require a `NeverToAny` coercion. // which would require a `NeverToAny` coercion.
hir::PatKind::Binding(_, _, _, _) hir::PatKind::Missing
| hir::PatKind::Binding(_, _, _, _)
| hir::PatKind::Struct(_, _, _) | hir::PatKind::Struct(_, _, _)
| hir::PatKind::TupleStruct(_, _, _) | hir::PatKind::TupleStruct(_, _, _)
| hir::PatKind::Tuple(_, _) | hir::PatKind::Tuple(_, _)

View file

@ -611,6 +611,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
for pat in pats { for pat in pats {
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
match &pat.kind { match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Binding(.., opt_sub_pat) => { PatKind::Binding(.., opt_sub_pat) => {
// If the opt_sub_pat is None, then the binding does not count as // If the opt_sub_pat is None, then the binding does not count as
// a wildcard for the purpose of borrowing discr. // 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::Expr(..)
| PatKind::Range(..) | PatKind::Range(..)
| PatKind::Never | PatKind::Never
| PatKind::Missing
| PatKind::Wild | PatKind::Wild
| PatKind::Err(_) => { | PatKind::Err(_) => {
// always ok // always ok

View file

@ -43,7 +43,7 @@ pub(super) struct Declaration<'a> {
impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> { impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> {
fn from(local: &'a hir::LetStmt<'a>) -> Self { 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 } } Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
} }
} }

View file

@ -117,7 +117,7 @@ fn typeck_with_inspect<'tcx>(
let id = tcx.local_def_id_to_hir_id(def_id); let id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(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. // Figure out what primary body this item has.
let body_id = node.body_id().unwrap_or_else(|| { let body_id = node.body_id().unwrap_or_else(|| {

View file

@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
let ty = match pat.kind { 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. // We allow any type here; we ensure that the type is uninhabited during match checking.
PatKind::Never => expected, PatKind::Never => expected,
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { 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`. // 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. // 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. // A malformed pattern doesn't have an expected type, so let's just accept any type.
| PatKind::Err(_) | PatKind::Err(_)
// Bindings also work with whatever the expected type is, // Bindings also work with whatever the expected type is,
@ -1032,7 +1034,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| PatKind::Tuple(..) | PatKind::Tuple(..)
| PatKind::Slice(..) => "binding", | PatKind::Slice(..) => "binding",
PatKind::Wild PatKind::Missing
| PatKind::Wild
| PatKind::Never | PatKind::Never
| PatKind::Binding(..) | PatKind::Binding(..)
| PatKind::Box(..) | PatKind::Box(..)

View file

@ -779,8 +779,7 @@ impl EarlyLintPass for AnonymousParameters {
} }
if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind { if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
for arg in sig.decl.inputs.iter() { for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind { if let ast::PatKind::Missing = arg.pat.kind {
if ident.name == kw::Empty {
let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span); let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
let (ty_snip, appl) = if let Ok(ref snip) = ty_snip { let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
@ -798,7 +797,6 @@ impl EarlyLintPass for AnonymousParameters {
} }
} }
} }
}
/// Check for use of attributes which have been deprecated. /// Check for use of attributes which have been deprecated.
#[derive(Clone)] #[derive(Clone)]

View file

@ -1201,7 +1201,8 @@ impl EarlyLintPass for UnusedParens {
// Do not lint on `(..)` as that will result in the other arms being useless. // Do not lint on `(..)` as that will result in the other arms being useless.
Paren(_) Paren(_)
// The other cases do not contain sub-patterns. // 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. // These are list-like patterns; parens can always be removed.
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
self.check_unused_parens_pat(cx, p, false, false, keep_space); self.check_unused_parens_pat(cx, p, false, false, keep_space);

View file

@ -207,7 +207,7 @@ impl<'tcx> Collector<'tcx> {
let sess = self.tcx.sess; let sess = self.tcx.sess;
if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) { if matches!(abi, ExternAbi::Rust) {
return; return;
} }

View file

@ -747,6 +747,9 @@ pub struct Ascription<'tcx> {
#[derive(Clone, Debug, HashStable, TypeVisitable)] #[derive(Clone, Debug, HashStable, TypeVisitable)]
pub enum PatKind<'tcx> { 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: `_`. /// A wildcard pattern: `_`.
Wild, Wild,
@ -812,23 +815,17 @@ pub enum PatKind<'tcx> {
}, },
/// Pattern obtained by converting a constant (inline or named) to its pattern /// 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 { ExpandedConstant {
/// [DefId] of the constant, we need this so that we have a /// [DefId] of the constant item.
/// 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.
def_id: DefId, def_id: DefId,
/// If `false`, then `def_id` points at a `const` item, otherwise it /// The pattern that the constant lowered to.
/// 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).
/// ///
/// Otherwise, the actual pattern that the constant lowered to. As with /// HACK: we need to keep the `DefId` of inline constants around for unsafety checking;
/// other constants, inline constants are matched structurally where /// therefore when a range pattern contains inline constants, we re-wrap the range pattern
/// possible. /// 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>>, subpattern: Box<Pat<'tcx>>,
}, },

View file

@ -250,7 +250,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
mut callback: impl FnMut(&'a Pat<'tcx>), mut callback: impl FnMut(&'a Pat<'tcx>),
) { ) {
match &pat.kind { match &pat.kind {
PatKind::Wild PatKind::Missing
| PatKind::Wild
| PatKind::Binding { subpattern: None, .. } | PatKind::Binding { subpattern: None, .. }
| PatKind::Constant { value: _ } | PatKind::Constant { value: _ }
| PatKind::Range(_) | PatKind::Range(_)

View file

@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> {
/// - coroutines /// - coroutines
Item(DefId), 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. /// 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 /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the

View file

@ -1265,9 +1265,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
| CCmseNonSecureCall | CCmseNonSecureCall
| CCmseNonSecureEntry | CCmseNonSecureEntry
| Unadjusted => false, | Unadjusted => false,
Rust | RustCall | RustCold | RustIntrinsic => { Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
tcx.sess.panic_strategy() == PanicStrategy::Unwind
}
} }
} }

View file

@ -143,25 +143,11 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
| ty::UnsafeBinder(_) => None, | ty::UnsafeBinder(_) => None,
ty::Adt(adt_def, _) => { ty::Adt(adt_def, _) => {
let did = adt_def.did(); if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
let try_local_did_span = |did: DefId| { Some(tcx.def_span(tcx.parent(dtor.did)))
if let Some(local) = did.as_local() {
tcx.source_span(local)
} else { } else {
tcx.def_span(did) Some(tcx.def_span(adt_def.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));
} 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))
} }
ty::Coroutine(did, _) ty::Coroutine(did, _)
| ty::CoroutineWitness(did, _) | ty::CoroutineWitness(did, _)

View file

@ -2,7 +2,7 @@
use std::{fmt, iter}; 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_apfloat::Float as _;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; 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 /// 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. /// cause an ICE that we otherwise may want to prevent.
pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> { pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
if tcx.features().intrinsics() if tcx.features().intrinsics() && tcx.has_attr(def_id, sym::rustc_intrinsic) {
&& (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
|| tcx.has_attr(def_id, sym::rustc_intrinsic))
{
let must_be_overridden = match tcx.hir_node_by_def_id(def_id) { let must_be_overridden = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
!has_body !has_body

View file

@ -145,7 +145,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
let arm = &self.thir[*arm]; let arm = &self.thir[*arm];
let value = match arm.pattern.kind { let value = match arm.pattern.kind {
PatKind::Constant { value } => value, 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 => if let PatKind::Constant { value } = subpattern.kind =>
{ {
value value

View file

@ -118,7 +118,7 @@ impl<'tcx> MatchPairTree<'tcx> {
let place = place_builder.try_to_place(cx); let place = place_builder.try_to_place(cx);
let mut subpairs = Vec::new(); let mut subpairs = Vec::new();
let test_case = match pattern.kind { 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 { PatKind::Or { ref pats } => Some(TestCase::Or {
pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
@ -201,39 +201,10 @@ impl<'tcx> MatchPairTree<'tcx> {
None 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); MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data);
None 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 } => { PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix( cx.prefix_slice_suffix(

View file

@ -920,6 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Constant { .. } PatKind::Constant { .. }
| PatKind::Range { .. } | PatKind::Range { .. }
| PatKind::Missing
| PatKind::Wild | PatKind::Wild
| PatKind::Never | PatKind::Never
| PatKind::Error(_) => {} | PatKind::Error(_) => {}

View file

@ -315,6 +315,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
fn visit_pat(&mut self, pat: &'a Pat<'tcx>) { fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
if self.in_union_destructure { if self.in_union_destructure {
match pat.kind { match pat.kind {
PatKind::Missing => unreachable!(),
// binding to a variable allows getting stuff out of variable // binding to a variable allows getting stuff out of variable
PatKind::Binding { .. } PatKind::Binding { .. }
// match is conditional on having this value // 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); visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt; self.inside_adt = old_inside_adt;
} }
PatKind::ExpandedConstant { def_id, is_inline, .. } => { PatKind::ExpandedConstant { def_id, .. } => {
if let Some(def) = def_id.as_local() if let Some(def) = def_id.as_local()
&& *is_inline && matches!(self.tcx.def_kind(def_id), DefKind::InlineConst)
{ {
self.visit_inner_body(def); self.visit_inner_body(def);
} }

View file

@ -676,7 +676,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
unpeeled_pat = subpattern; 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 DefKind::Const = self.tcx.def_kind(def_id)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
// We filter out paths with multiple path::segments. // We filter out paths with multiple path::segments.
@ -1296,7 +1296,8 @@ fn report_non_exhaustive_match<'p, 'tcx>(
for &arm in arms { for &arm in arms {
let arm = &thir.arms[arm]; 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) && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
// We filter out paths with multiple path::segments. // We filter out paths with multiple path::segments.
&& snippet.chars().all(|c| c.is_alphanumeric() || c == '_') && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')

View file

@ -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( fn field_pats(

View file

@ -13,14 +13,15 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, LangItem, RangeEnd}; use rustc_hir::{self as hir, LangItem, RangeEnd};
use rustc_index::Idx; use rustc_index::Idx;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::thir::{ use rustc_middle::thir::{
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
}; };
use rustc_middle::ty::layout::IntegerExt; 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_middle::{bug, span_bug};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::DefId;
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -124,7 +125,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
expr: Option<&'tcx hir::PatExpr<'tcx>>, expr: Option<&'tcx hir::PatExpr<'tcx>>,
// Out-parameters collecting extra data to be reapplied by the caller // Out-parameters collecting extra data to be reapplied by the caller
ascriptions: &mut Vec<Ascription<'tcx>>, ascriptions: &mut Vec<Ascription<'tcx>>,
inline_consts: &mut Vec<LocalDefId>, expanded_consts: &mut Vec<DefId>,
) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> { ) -> Result<Option<PatRangeBoundary<'tcx>>, ErrorGuaranteed> {
let Some(expr) = expr else { return Ok(None) }; let Some(expr) = expr else { return Ok(None) };
@ -139,10 +140,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ascriptions.push(ascription); ascriptions.push(ascription);
kind = subpattern.kind; kind = subpattern.kind;
} }
PatKind::ExpandedConstant { is_inline, def_id, subpattern } => { PatKind::ExpandedConstant { def_id, subpattern } => {
if is_inline { expanded_consts.push(def_id);
inline_consts.extend(def_id.as_local());
}
kind = subpattern.kind; kind = subpattern.kind;
} }
_ => break, _ => break,
@ -221,10 +220,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// Collect extra data while lowering the endpoints, to be reapplied later. // Collect extra data while lowering the endpoints, to be reapplied later.
let mut ascriptions = vec![]; let mut ascriptions = vec![];
let mut inline_consts = vec![]; let mut expanded_consts = vec![];
let mut lower_endpoint = 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 lo = lower_endpoint(lo_expr)?.unwrap_or(PatRangeBoundary::NegInfinity);
let hi = lower_endpoint(hi_expr)?.unwrap_or(PatRangeBoundary::PosInfinity); 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 // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
// constants somewhere. Have them on the range pattern. // constants somewhere. Have them on the range pattern.
for ascription in ascriptions { for ascription in ascriptions {
kind = PatKind::AscribeUserType { let subpattern = Box::new(Pat { span, ty, kind });
ascription, kind = PatKind::AscribeUserType { ascription, subpattern };
subpattern: Box::new(Pat { span, ty, kind }),
};
} }
for def in inline_consts { for def_id in expanded_consts {
kind = PatKind::ExpandedConstant { let subpattern = Box::new(Pat { span, ty, kind });
def_id: def.to_def_id(), kind = PatKind::ExpandedConstant { def_id, subpattern };
is_inline: true,
subpattern: Box::new(Pat { span, ty, kind }),
};
} }
Ok(kind) Ok(kind)
} }
@ -290,6 +284,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let mut span = pat.span; let mut span = pat.span;
let kind = match pat.kind { let kind = match pat.kind {
hir::PatKind::Missing => PatKind::Missing,
hir::PatKind::Wild => PatKind::Wild, hir::PatKind::Wild => PatKind::Wild,
hir::PatKind::Never => PatKind::Never, hir::PatKind::Never => PatKind::Never,
@ -567,15 +563,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// Lower the named constant to a THIR pattern. // Lower the named constant to a THIR pattern.
let args = self.typeck_results.node_args(id); let args = self.typeck_results.node_args(id);
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
let subpattern = self.const_to_pat(c, ty, id, span); let mut 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 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 })
};
// If this is an associated constant with an explicit user-written // If this is an associated constant with an explicit user-written
// type, add an ascription node (e.g. `<Foo<'a> as MyTrait>::CONST`). // 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 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 typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
let parent_args = let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id));
let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args; 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 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 // Apply a type ascription for the inline constant.
// of lowering an inline const block. let annotation = {
PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } 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: /// Lowers the kinds of "expression" that can appear in a HIR pattern:
@ -635,16 +642,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
expr: &'tcx hir::PatExpr<'tcx>, expr: &'tcx hir::PatExpr<'tcx>,
pat_ty: Option<Ty<'tcx>>, pat_ty: Option<Ty<'tcx>>,
) -> PatKind<'tcx> { ) -> PatKind<'tcx> {
let (lit, neg) = match &expr.kind { match &expr.kind {
hir::PatExprKind::Path(qpath) => { hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
}
hir::PatExprKind::ConstBlock(anon_const) => { 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), hir::PatExprKind::Lit { lit, negated } => {
};
// We handle byte string literal patterns by using the pattern's type instead of the // 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, // 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 // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
@ -670,8 +673,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
Some(pat_ty) => pat_ty, Some(pat_ty) => pat_ty,
None => self.typeck_results.node_type(expr.hir_id), None => self.typeck_results.node_type(expr.hir_id),
}; };
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg: *negated };
let constant = self.tcx.at(expr.span).lit_to_const(lit_input); 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 self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
} }
} }
}
}

View file

@ -664,6 +664,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "kind: PatKind {", depth_lvl); print_indented!(self, "kind: PatKind {", depth_lvl);
match pat_kind { match pat_kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => { PatKind::Wild => {
print_indented!(self, "Wild", depth_lvl + 1); 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, format!("value: {:?}", value), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); 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, "ExpandedConstant {", depth_lvl + 1);
print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); 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); print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1);

View file

@ -2987,9 +2987,7 @@ impl<'a> Parser<'a> {
} }
match ty { match ty {
Ok(ty) => { Ok(ty) => {
let ident = Ident::new(kw::Empty, this.prev_token.span); let pat = this.mk_pat(ty.span, PatKind::Missing);
let bm = BindingMode::NONE;
let pat = this.mk_pat_ident(ty.span, bm, ident);
(pat, ty) (pat, ty)
} }
// If this is a C-variadic argument and we hit an error, return the error. // If this is a C-variadic argument and we hit an error, return the error.

View file

@ -75,10 +75,11 @@ impl<'a> Parser<'a> {
let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) { 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| { self.collect_tokens(None, attrs, force_collect, |this, attrs| {
let super_span = this.token.span;
this.expect_keyword(exp!(Super))?; this.expect_keyword(exp!(Super))?;
this.psess.gated_spans.gate(sym::super_let, this.prev_token.span);
this.expect_keyword(exp!(Let))?; 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); let trailing = Trailing::from(capture_semi && this.token == token::Semi);
Ok(( Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), 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) { } else if self.token.is_keyword(kw::Let) {
self.collect_tokens(None, attrs, force_collect, |this, attrs| { self.collect_tokens(None, attrs, force_collect, |this, attrs| {
this.expect_keyword(exp!(Let))?; 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); let trailing = Trailing::from(capture_semi && this.token == token::Semi);
Ok(( Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
@ -294,7 +295,7 @@ impl<'a> Parser<'a> {
force_collect: ForceCollect, force_collect: ForceCollect,
) -> PResult<'a, Stmt> { ) -> PResult<'a, Stmt> {
let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| { 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? // FIXME - maybe capture semicolon in recovery?
Ok(( Ok((
this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), 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. /// Parses a local variable declaration.
fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> { fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, P<Local>> {
let lo = self.prev_token.span; let lo = super_.unwrap_or(self.prev_token.span);
if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) { 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) }); 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 }; let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
Ok(P(ast::Local { Ok(P(ast::Local {
super_,
ty, ty,
pat, pat,
kind, kind,

View file

@ -1598,7 +1598,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
if target == Target::ForeignMod if target == Target::ForeignMod
&& let hir::Node::Item(item) = self.tcx.hir_node(hir_id) && let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
&& !matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) && !matches!(abi, ExternAbi::Rust)
{ {
return; return;
} }

View file

@ -295,6 +295,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
record_variants!( record_variants!(
(self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind), (self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
[ [
Missing,
Wild, Wild,
Binding, Binding,
Struct, Struct,
@ -597,6 +598,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
record_variants!( record_variants!(
(self, p, p.kind, None, ast, Pat, PatKind), (self, p, p.kind, None, ast, Pat, PatKind),
[ [
Missing,
Wild, Wild,
Ident, Ident,
Struct, Struct,

View file

@ -96,7 +96,7 @@ use rustc_middle::query::Providers;
use rustc_middle::span_bug; use rustc_middle::span_bug;
use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint; use rustc_session::lint;
use rustc_span::{BytePos, Span, Symbol, kw, sym}; use rustc_span::{BytePos, Span, Symbol, sym};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use self::LiveNodeKind::*; use self::LiveNodeKind::*;
@ -1481,9 +1481,6 @@ impl<'tcx> Liveness<'_, 'tcx> {
fn should_warn(&self, var: Variable) -> Option<String> { fn should_warn(&self, var: Variable) -> Option<String> {
let name = self.ir.variable_name(var); let name = self.ir.variable_name(var);
if name == kw::Empty {
return None;
}
let name = name.as_str(); let name = name.as_str();
if name.as_bytes()[0] == b'_' { if name.as_bytes()[0] == b'_' {
return None; return None;

View file

@ -460,7 +460,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
PatKind::AscribeUserType { subpattern, .. } PatKind::AscribeUserType { subpattern, .. }
| PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), 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; ctor = Wildcard;
fields = vec![]; fields = vec![];
arity = 0; arity = 0;

View file

@ -4009,22 +4009,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
self.report_error(ident.span, error(ident)); self.report_error(ident.span, error(ident));
} }
// Record as bound if it's valid: // Record as bound.
let ident_valid = ident.name != kw::Empty;
if ident_valid {
bindings.last_mut().unwrap().1.insert(ident); bindings.last_mut().unwrap().1.insert(ident);
}
if already_bound_or { if already_bound_or {
// `Variant1(a) | Variant2(a)`, ok // `Variant1(a) | Variant2(a)`, ok
// Reuse definition from the first `a`. // Reuse definition from the first `a`.
self.innermost_rib_bindings(ValueNS)[&ident] self.innermost_rib_bindings(ValueNS)[&ident]
} else { } else {
// A completely fresh binding is added to the set.
let res = Res::Local(pat_id); 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 res
} }
} }

View file

@ -491,7 +491,6 @@ impl RustcInternal for Abi {
Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall, Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall,
Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry, Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry,
Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind }, Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind },
Abi::RustIntrinsic => rustc_abi::ExternAbi::RustIntrinsic,
Abi::RustCall => rustc_abi::ExternAbi::RustCall, Abi::RustCall => rustc_abi::ExternAbi::RustCall,
Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted, Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted,
Abi::RustCold => rustc_abi::ExternAbi::RustCold, Abi::RustCold => rustc_abi::ExternAbi::RustCold,

View file

@ -871,7 +871,6 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry,
ExternAbi::System { unwind } => Abi::System { unwind }, ExternAbi::System { unwind } => Abi::System { unwind },
ExternAbi::RustIntrinsic => Abi::RustIntrinsic,
ExternAbi::RustCall => Abi::RustCall, ExternAbi::RustCall => Abi::RustCall,
ExternAbi::Unadjusted => Abi::Unadjusted, ExternAbi::Unadjusted => Abi::Unadjusted,
ExternAbi::RustCold => Abi::RustCold, ExternAbi::RustCold => Abi::RustCold,

View file

@ -1093,7 +1093,6 @@ pub enum Abi {
CCmseNonSecureCall, CCmseNonSecureCall,
CCmseNonSecureEntry, CCmseNonSecureEntry,
System { unwind: bool }, System { unwind: bool },
RustIntrinsic,
RustCall, RustCall,
Unadjusted, Unadjusted,
RustCold, RustCold,

View file

@ -1,6 +1,6 @@
use rustc_abi::{ use rustc_abi::{
BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
TyAbiInterface, TyAndLayout, Variants, TyAndLayout, Variants,
}; };
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; 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 where
Ty: TyAbiInterface<'a, C> + Copy, Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec, C: HasDataLayout + HasTargetSpec,
{ {
if abi == ExternAbi::RustIntrinsic {
return;
}
let grlen = cx.data_layout().pointer_size.bits(); let grlen = cx.data_layout().pointer_size.bits();
for arg in fn_abi.args.iter_mut() { for arg in fn_abi.args.iter_mut() {

View file

@ -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 where
Ty: TyAbiInterface<'a, C> + Copy, Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec, C: HasDataLayout + HasTargetSpec,
{ {
let spec = cx.target_spec(); let spec = cx.target_spec();
match &*spec.arch { match &*spec.arch {
"x86" => x86::compute_rust_abi_info(cx, self, abi), "x86" => x86::compute_rust_abi_info(cx, self),
"riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi), "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self),
"loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi), "loongarch64" => loongarch::compute_rust_abi_info(cx, self),
"aarch64" => aarch64::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 // Note that the intrinsic ABI is exempt here as those are not
// real functions anyway, and the backend expects very specific types. // real functions anyway, and the backend expects very specific types.
if abi != ExternAbi::RustIntrinsic if spec.simd_types_indirect && !can_pass_simd_directly(arg) {
&& spec.simd_types_indirect
&& !can_pass_simd_directly(arg)
{
arg.make_indirect(); arg.make_indirect();
} }
} }

View file

@ -5,8 +5,8 @@
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
use rustc_abi::{ use rustc_abi::{
BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
TyAbiInterface, TyAndLayout, Variants, TyAndLayout, Variants,
}; };
use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform}; 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 where
Ty: TyAbiInterface<'a, C> + Copy, Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec, C: HasDataLayout + HasTargetSpec,
{ {
if abi == ExternAbi::RustIntrinsic {
return;
}
let xlen = cx.data_layout().pointer_size.bits(); let xlen = cx.data_layout().pointer_size.bits();
for arg in fn_abi.args.iter_mut() { for arg in fn_abi.args.iter_mut() {

View file

@ -1,6 +1,6 @@
use rustc_abi::{ use rustc_abi::{
AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAbiInterface,
TyAbiInterface, TyAndLayout, TyAndLayout,
}; };
use crate::callconv::{ArgAttribute, FnAbi, PassMode}; 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 where
Ty: TyAbiInterface<'a, C> + Copy, Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec, C: HasDataLayout + HasTargetSpec,
@ -201,10 +201,7 @@ where
// Avoid returning floats in x87 registers on x86 as loading and storing from x87 // 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 // registers will quiet signalling NaNs. Also avoid using SSE registers since they
// are not always available (depending on target features). // are not always available (depending on target features).
if !fn_abi.ret.is_ignore() if !fn_abi.ret.is_ignore() {
// Intrinsics themselves are not "real" functions, so theres no need to change their ABIs.
&& abi != ExternAbi::RustIntrinsic
{
let has_float = match fn_abi.ret.layout.backend_repr { let has_float = match fn_abi.ret.layout.backend_repr {
BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)), BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)),
BackendRepr::ScalarPair(s1, s2) => { BackendRepr::ScalarPair(s1, s2) => {

View file

@ -2962,14 +2962,9 @@ impl Target {
pub fn is_abi_supported(&self, abi: ExternAbi) -> bool { pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
use ExternAbi::*; use ExternAbi::*;
match abi { match abi {
Rust Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => {
| C { .. } true
| System { .. } }
| RustIntrinsic
| RustCall
| Unadjusted
| Cdecl { .. }
| RustCold => true,
EfiApi => { EfiApi => {
["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..]) ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
} }

View file

@ -244,7 +244,7 @@ fn fn_sig_for_fn_abi<'tcx>(
fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv { fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv {
use rustc_abi::ExternAbi::*; use rustc_abi::ExternAbi::*;
match tcx.sess.target.adjust_abi(abi, c_variadic) { 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 // This is intentionally not using `Conv::Cold`, as that has to preserve
// even SIMD registers, which is generally not a good trade-off. // 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(); let tcx = cx.tcx();
if abi.is_rustic_abi() { 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 // 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 // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes

View file

@ -8,6 +8,7 @@
//! Note: any changes to the constness of intrinsics should be discussed with the language team. //! Note: any changes to the constness of intrinsics should be discussed with the language team.
//! This includes changes in the stability of the constness. //! 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" //! 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 //! 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 //! implementation from <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to

View file

@ -52,9 +52,8 @@ with any regular function.
Various intrinsics have native MIR operations that they correspond to. Instead of requiring 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 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 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" at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`.
or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
anymore after MIR analyses.
## Intrinsics without fallback logic ## Intrinsics without fallback logic
@ -70,28 +69,3 @@ These are written without a body:
#[rustc_intrinsic] #[rustc_intrinsic]
pub fn abort() -> !; 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.

View file

@ -11,7 +11,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability}; use rustc_hir::{BodyId, Mutability};
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_metadata::rendered_const; use rustc_metadata::rendered_const;
use rustc_middle::span_bug; use rustc_middle::span_bug;
@ -687,8 +686,6 @@ impl Item {
hir::FnHeader { hir::FnHeader {
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features { safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
hir::HeaderSafety::SafeTargetFeatures hir::HeaderSafety::SafeTargetFeatures
} else if abi == ExternAbi::RustIntrinsic {
intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
} else { } else {
safety.into() safety.into()
}, },

View file

@ -304,6 +304,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
Symbol::intern(&match &p.kind { Symbol::intern(&match &p.kind {
// FIXME(never_patterns): does this make sense? // FIXME(never_patterns): does this make sense?
PatKind::Missing => unreachable!(),
PatKind::Wild PatKind::Wild
| PatKind::Err(_) | PatKind::Err(_)
| PatKind::Never | PatKind::Never

View file

@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
pats.iter().all(unary_pattern) pats.iter().all(unary_pattern)
} }
match &pat.kind { match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Slice(_, _, _) PatKind::Slice(_, _, _)
| PatKind::Range(_, _, _) | PatKind::Range(_, _, _)
| PatKind::Binding(..) | PatKind::Binding(..)

View file

@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>(
impl<'a> NormalizedPat<'a> { impl<'a> NormalizedPat<'a> {
fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self { fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
match pat.kind { match pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild, PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
PatKind::Binding(.., Some(pat)) PatKind::Binding(.., Some(pat))
| PatKind::Box(pat) | PatKind::Box(pat)

View file

@ -406,6 +406,7 @@ impl<'a> PatState<'a> {
pats.iter().map(|p| p.pat), pats.iter().map(|p| p.pat),
), ),
PatKind::Missing => unreachable!(),
PatKind::Wild PatKind::Wild
| PatKind::Binding(_, _, _, None) | PatKind::Binding(_, _, _, None)
| PatKind::Expr(_) | PatKind::Expr(_)

View file

@ -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..]`. // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
let changed = match &mut focus_kind { let changed = match &mut focus_kind {
Missing => unreachable!(),
// These pattern forms are "leafs" and do not have sub-patterns. // These pattern forms are "leafs" and do not have sub-patterns.
// Therefore they are not some form of constructor `C`, // Therefore they are not some form of constructor `C`,
// with which a pattern `C(p_0)` may be formed, // with which a pattern `C(p_0)` may be formed,

View file

@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
} }
match pat.value.kind { match pat.value.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild => kind!("Wild"), PatKind::Wild => kind!("Wild"),
PatKind::Never => kind!("Never"), PatKind::Never => kind!("Never"),
PatKind::Binding(ann, _, name, sub) => { PatKind::Binding(ann, _, name, sub) => {

View file

@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool {
pub fn eq_pat(l: &Pat, r: &Pat) -> bool { pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
use PatKind::*; use PatKind::*;
match (&l.kind, &r.kind) { match (&l.kind, &r.kind) {
(Missing, _) | (_, Missing) => unreachable!(),
(Paren(l), _) => eq_pat(l, r), (Paren(l), _) => eq_pat(l, r),
(_, Paren(r)) => eq_pat(l, r), (_, Paren(r)) => eq_pat(l, r),
(Wild, Wild) | (Rest, Rest) => true, (Wild, Wild) | (Rest, Rest) => true,

View file

@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
pub fn hash_pat(&mut self, pat: &Pat<'_>) { pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s); std::mem::discriminant(&pat.kind).hash(&mut self.s);
match pat.kind { match pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => { PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
std::mem::discriminant(&by_ref).hash(&mut self.s); std::mem::discriminant(&by_ref).hash(&mut self.s);
std::mem::discriminant(&mutability).hash(&mut self.s); std::mem::discriminant(&mutability).hash(&mut self.s);

View file

@ -1858,6 +1858,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
} }
match pat.kind { match pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. 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::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),

View file

@ -400,7 +400,6 @@ pub enum FnAbi {
Rust, Rust,
RustCall, RustCall,
RustCold, RustCold,
RustIntrinsic,
Stdcall, Stdcall,
StdcallUnwind, StdcallUnwind,
System, System,
@ -457,7 +456,6 @@ impl FnAbi {
s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS, 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_call => FnAbi::RustCall,
s if *s == sym::rust_dash_cold => FnAbi::RustCold, 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::Rust => FnAbi::Rust,
s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind, s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
s if *s == sym::stdcall => FnAbi::Stdcall, s if *s == sym::stdcall => FnAbi::Stdcall,
@ -500,7 +498,6 @@ impl FnAbi {
FnAbi::Rust => "Rust", FnAbi::Rust => "Rust",
FnAbi::RustCall => "rust-call", FnAbi::RustCall => "rust-call",
FnAbi::RustCold => "rust-cold", FnAbi::RustCold => "rust-cold",
FnAbi::RustIntrinsic => "rust-intrinsic",
FnAbi::Stdcall => "stdcall", FnAbi::Stdcall => "stdcall",
FnAbi::StdcallUnwind => "stdcall-unwind", FnAbi::StdcallUnwind => "stdcall-unwind",
FnAbi::System => "system", FnAbi::System => "system",

View file

@ -59,19 +59,7 @@ impl Evaluator<'_> {
let function_data = self.db.function_data(def); let function_data = self.db.function_data(def);
let attrs = self.db.attrs(def.into()); let attrs = self.db.attrs(def.into());
let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists() 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,
},
});
if is_intrinsic { if is_intrinsic {
return self.exec_intrinsic( return self.exec_intrinsic(

View file

@ -18,7 +18,6 @@ use hir_def::{
TypeOrConstParamId, TypeOrConstParamId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use intern::sym;
use rustc_abi::TargetDataLayout; use rustc_abi::TargetDataLayout;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -303,19 +302,7 @@ pub fn is_fn_unsafe_to_call(
let loc = func.lookup(db.upcast()); let loc = func.lookup(db.upcast());
match loc.container { match loc.container {
hir_def::ItemContainerId::ExternBlockId(block) => { 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
}
} else {
// Function in an `extern` block are always unsafe to call, except when // Function in an `extern` block are always unsafe to call, except when
// it is marked as `safe`. // it is marked as `safe`.
if data.is_safe() { if data.is_safe() {
@ -324,7 +311,6 @@ pub fn is_fn_unsafe_to_call(
Unsafety::Unsafe Unsafety::Unsafe
} }
} }
}
_ => Unsafety::Safe, _ => Unsafety::Safe,
} }
} }

View file

@ -36,7 +36,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
"wasm", "wasm",
"system", "system",
"system-unwind", "system-unwind",
"rust-intrinsic",
"rust-call", "rust-call",
"unadjusted", "unadjusted",
]; ];

View file

@ -6945,9 +6945,8 @@ fn hover_feature() {
Various intrinsics have native MIR operations that they correspond to. Instead of requiring 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 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 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" at all. These intrinsics only make sense without a body, and can be as a `#[rustc_intrinsic]`.
or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
anymore after MIR analyses.
## Intrinsics without fallback logic ## 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 `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
invoke the body. 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.
"#]], "#]],
) )
} }

View file

@ -125,7 +125,6 @@ define_symbols! {
riscv_dash_interrupt_dash_s = "riscv-interrupt-s", riscv_dash_interrupt_dash_s = "riscv-interrupt-s",
rust_dash_call = "rust-call", rust_dash_call = "rust-call",
rust_dash_cold = "rust-cold", rust_dash_cold = "rust-cold",
rust_dash_intrinsic = "rust-intrinsic",
stdcall_dash_unwind = "stdcall-unwind", stdcall_dash_unwind = "stdcall-unwind",
system_dash_unwind = "system-unwind", system_dash_unwind = "system-unwind",
sysv64_dash_unwind = "sysv64-unwind", sysv64_dash_unwind = "sysv64-unwind",

View file

@ -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 { pub(crate) fn is_named_param(param: &ast::Param) -> bool {
if let ast::PatKind::Ident(_, ident, _) = param.pat.kind { !matches!(param.pat.kind, ast::PatKind::Missing)
ident.name != symbol::kw::Empty
} else {
true
}
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]

View file

@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern(
fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool { fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
match &pat.kind { match &pat.kind {
ast::PatKind::Missing => unreachable!(),
ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => { ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
true true
} }
@ -100,6 +101,7 @@ impl Rewrite for Pat {
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
match self.kind { match self.kind {
PatKind::Missing => unreachable!(),
PatKind::Or(ref pats) => { PatKind::Or(ref pats) => {
let pat_strs = pats let pat_strs = pats
.iter() .iter()

View file

@ -35,9 +35,8 @@ pub struct m64x2([i64; 2]);
#[repr(simd)] #[repr(simd)]
pub struct m64x4([i64; 4]); pub struct m64x4([i64; 4]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_bitmask<V, B>(mask: V) -> B; unsafe fn simd_bitmask<V, B>(mask: V) -> B;
}
// CHECK-LABEL: bitmask_m8x16 // CHECK-LABEL: bitmask_m8x16
#[no_mangle] #[no_mangle]

View file

@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
#[repr(simd)] #[repr(simd)]
pub struct pf64x4([*const f64; 4]); pub struct pf64x4([*const f64; 4]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V; unsafe fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V;
}
// CHECK-LABEL: gather_f64x4 // CHECK-LABEL: gather_f64x4
#[no_mangle] #[no_mangle]

View file

@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
#[repr(simd)] #[repr(simd)]
pub struct m64x4([i64; 4]); pub struct m64x4([i64; 4]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T; unsafe fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
}
// CHECK-LABEL: load_i8x16 // CHECK-LABEL: load_i8x16
#[no_mangle] #[no_mangle]

View file

@ -20,10 +20,10 @@ use minicore::*;
#[repr(simd)] #[repr(simd)]
pub struct mask8x16([i8; 16]); pub struct mask8x16([i8; 16]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_reduce_all<T>(x: T) -> bool; unsafe fn simd_reduce_all<T>(x: T) -> bool;
fn simd_reduce_any<T>(x: T) -> bool; #[rustc_intrinsic]
} unsafe fn simd_reduce_any<T>(x: T) -> bool;
// CHECK-LABEL: mask_reduce_all: // CHECK-LABEL: mask_reduce_all:
#[no_mangle] #[no_mangle]

View file

@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
#[repr(simd)] #[repr(simd)]
pub struct m64x4([i64; 4]); pub struct m64x4([i64; 4]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T); unsafe fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
}
// CHECK-LABEL: store_i8x16 // CHECK-LABEL: store_i8x16
#[no_mangle] #[no_mangle]

View file

@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
#[repr(simd)] #[repr(simd)]
pub struct pf64x4([*mut f64; 4]); pub struct pf64x4([*mut f64; 4]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M); unsafe fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M);
}
// CHECK-LABEL: scatter_f64x4 // CHECK-LABEL: scatter_f64x4
#[no_mangle] #[no_mangle]

View file

@ -48,9 +48,8 @@ pub struct f64x8([f64; 8]);
#[repr(simd)] #[repr(simd)]
pub struct m64x8([i64; 8]); pub struct m64x8([i64; 8]);
extern "rust-intrinsic" { #[rustc_intrinsic]
fn simd_select<M, V>(mask: M, a: V, b: V) -> V; unsafe fn simd_select<M, V>(mask: M, a: V, b: V) -> V;
}
// CHECK-LABEL: select_i8x16 // CHECK-LABEL: select_i8x16
#[no_mangle] #[no_mangle]

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