Auto merge of #139482 - Zalathar:rollup-h2ht1y6, r=Zalathar
Rollup of 9 pull requests Successful merges: - #139035 (Add new `PatKind::Missing` variants) - #139108 (Simplify `thir::PatKind::ExpandedConstant`) - #139112 (Implement `super let`) - #139365 (Default auto traits: fix perf) - #139397 (coverage: Build the CGU's global file table as late as possible) - #139455 ( Remove support for `extern "rust-intrinsic"` blocks) - #139461 (Stop calling `source_span` query in significant drop order code) - #139465 (add sret handling for scalar autodiff) - #139466 (Trivial tweaks to stop tracking source span directly) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
e643f59f6d
166 changed files with 1790 additions and 1636 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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<_>>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(); } }
|
||||||
```
|
```
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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`",
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(_, _)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(|| {
|
||||||
|
|
|
@ -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(..)
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -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(_)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, _)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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(_) => {}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 == '_')
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -1093,7 +1093,6 @@ pub enum Abi {
|
||||||
CCmseNonSecureCall,
|
CCmseNonSecureCall,
|
||||||
CCmseNonSecureEntry,
|
CCmseNonSecureEntry,
|
||||||
System { unwind: bool },
|
System { unwind: bool },
|
||||||
RustIntrinsic,
|
|
||||||
RustCall,
|
RustCall,
|
||||||
Unadjusted,
|
Unadjusted,
|
||||||
RustCold,
|
RustCold,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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[..])
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
|
||||||
|
|
|
@ -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()
|
||||||
},
|
},
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(..)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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(_)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
];
|
];
|
||||||
|
|
|
@ -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.
|
|
||||||
|
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue