diff options
Diffstat (limited to 'compiler')
63 files changed, 1282 insertions, 856 deletions
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs new file mode 100644 index 00000000000..2cf7648a859 --- /dev/null +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -0,0 +1,136 @@ +use std::fmt; + +#[cfg(feature = "nightly")] +use rustc_macros::HashStable_Generic; + +use crate::ExternAbi; + +/// Calling convention to determine codegen +/// +/// CanonAbi erases certain distinctions ExternAbi preserves, but remains target-dependent. +/// There are still both target-specific variants and aliasing variants, though much fewer. +/// The reason for this step is the frontend may wish to show an ExternAbi but implement that ABI +/// using a different ABI than the string per se, or describe irrelevant differences, e.g. +/// - extern "system" +/// - extern "cdecl" +/// - extern "C-unwind" +/// In that sense, this erases mere syntactic distinctions to create a canonical *directive*, +/// rather than picking the "actual" ABI. +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum CanonAbi { + // NOTE: the use of nested variants for some ABIs is for many targets they don't matter, + // and this pushes the complexity of their reasoning to target-specific code, + // allowing a `match` to easily exhaustively ignore these subcategories of variants. + // Otherwise it is very tempting to avoid matching exhaustively! + C, + Rust, + RustCold, + + /// ABIs relevant to 32-bit Arm targets + Arm(ArmCall), + /// ABI relevant to GPUs: the entry point for a GPU kernel + GpuKernel, + + /// ABIs relevant to bare-metal interrupt targets + // FIXME(workingjubilee): a particular reason for this nesting is we might not need these? + // interrupt ABIs should have the same properties: + // - uncallable by Rust calls, as LLVM rejects it in most cases + // - uses a preserve-all-registers *callee* convention + // - should always return `-> !` (effectively... it can't use normal `ret`) + // what differs between targets is + // - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically + // - may need special prologues/epilogues for some interrupts, without affecting "call ABI" + Interrupt(InterruptKind), + + /// ABIs relevant to Windows or x86 targets + X86(X86Call), +} + +impl fmt::Display for CanonAbi { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.to_erased_extern_abi().as_str().fmt(f) + } +} + +impl CanonAbi { + /// convert to the ExternAbi that *shares a string* with this CanonAbi + /// + /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls. + /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values, + /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data. + const fn to_erased_extern_abi(self) -> ExternAbi { + match self { + CanonAbi::C => ExternAbi::C { unwind: false }, + CanonAbi::Rust => ExternAbi::Rust, + CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, + ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, + }, + CanonAbi::GpuKernel => ExternAbi::GpuKernel, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => ExternAbi::AvrInterrupt, + InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => ExternAbi::Msp430Interrupt, + InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM, + InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS, + InterruptKind::X86 => ExternAbi::X86Interrupt, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => ExternAbi::Fastcall { unwind: false }, + X86Call::Stdcall => ExternAbi::Stdcall { unwind: false }, + X86Call::SysV64 => ExternAbi::SysV64 { unwind: false }, + X86Call::Thiscall => ExternAbi::Thiscall { unwind: false }, + X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false }, + X86Call::Win64 => ExternAbi::Win64 { unwind: false }, + }, + } + } +} + +/// Callee codegen for interrupts +/// +/// This is named differently from the "Call" enums because it is different: +/// these "ABI" differences are not relevant to callers, since there is "no caller". +/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar. +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum InterruptKind { + Avr, + AvrNonBlocking, + Msp430, + RiscvMachine, + RiscvSupervisor, + X86, +} + +/// ABIs defined for x86-{32,64} +/// +/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now? +#[derive(Clone, Copy, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum X86Call { + /// "fastcall" has both GNU and Windows variants + Fastcall, + /// "stdcall" has both GNU and Windows variants + Stdcall, + SysV64, + Thiscall, + Vectorcall, + Win64, +} + +/// ABIs defined for 32-bit Arm +#[derive(Copy, Clone, Debug)] +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum ArmCall { + Aapcs, + CCmseNonSecureCall, + CCmseNonSecureEntry, +} diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 55f4845d216..c48920e5f1b 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -7,6 +7,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable}; +use crate::AbiFromStrErr; + #[cfg(test)] mod tests; @@ -99,11 +101,6 @@ macro_rules! abi_impls { } } -#[derive(Debug)] -pub enum AbiFromStrErr { - Unknown, -} - abi_impls! { ExternAbi = { C { unwind: false } =><= "C", diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 59b74d29221..b806d0aba31 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -55,13 +55,14 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic}; mod callconv; +mod canon_abi; +mod extern_abi; mod layout; #[cfg(test)] mod tests; -mod extern_abi; - pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; +pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; pub use extern_abi::{ExternAbi, all_names}; #[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; @@ -1895,3 +1896,11 @@ pub enum StructKind { /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag). Prefixed(Size, Align), } + +#[derive(Clone, Debug)] +pub enum AbiFromStrErr { + /// not a known ABI + Unknown, + /// no "-unwind" variant can be used here + NoExplicitUnwind, +} diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7b103126e45..c9a8adec31a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -99,8 +99,15 @@ pub struct Path { impl PartialEq<Symbol> for Path { #[inline] - fn eq(&self, symbol: &Symbol) -> bool { - matches!(&self.segments[..], [segment] if segment.ident.name == *symbol) + fn eq(&self, name: &Symbol) -> bool { + if let [segment] = self.segments.as_ref() + && segment.args.is_none() + && segment.ident.name == *name + { + true + } else { + false + } } } @@ -120,17 +127,6 @@ impl Path { Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } - pub fn is_ident(&self, name: Symbol) -> bool { - if let [segment] = self.segments.as_ref() - && segment.args.is_none() - && segment.ident.name == name - { - true - } else { - false - } - } - pub fn is_global(&self) -> bool { self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } @@ -2465,6 +2461,39 @@ impl TyKind { None } } + + /// Returns `true` if this type is considered a scalar primitive (e.g., + /// `i32`, `u8`, `bool`, etc). + /// + /// This check is based on **symbol equality** and does **not** remove any + /// path prefixes or references. If a type alias or shadowing is present + /// (e.g., `type i32 = CustomType;`), this method will still return `true` + /// for `i32`, even though it may not refer to the primitive type. + pub fn maybe_scalar(&self) -> bool { + let Some(ty_sym) = self.is_simple_path() else { + // unit type + return self.is_unit(); + }; + matches!( + ty_sym, + sym::i8 + | sym::i16 + | sym::i32 + | sym::i64 + | sym::i128 + | sym::u8 + | sym::u16 + | sym::u32 + | sym::u64 + | sym::u128 + | sym::f16 + | sym::f32 + | sym::f64 + | sym::f128 + | sym::char + | sym::bool + ) + } } /// A pattern type pattern. diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9f3aed9216c..537d4a2a6af 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::ops::ControlFlow; use std::sync::Arc; @@ -1199,11 +1198,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); - assert_matches!( - coroutine_kind, - CoroutineKind::Async { .. }, - "only async closures are supported currently" - ); + let coroutine_desugaring = match coroutine_kind { + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, + CoroutineKind::AsyncGen { span, .. } => { + span_bug!(span, "only async closures and `iter!` closures are supported currently") + } + }; let body = self.with_new_scopes(fn_decl_span, |this| { let inner_decl = @@ -1247,7 +1248,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Lower this as a `CoroutineClosure`. That will ensure that HIR typeck // knows that a `FnDecl` output type like `-> &str` actually means // "coroutine that returns &str", rather than directly returning a `&str`. - kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async), + kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring), constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 915613a3913..3682d25d341 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -477,11 +477,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { for span in spans { if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines)) && (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks)) + && (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr)) { #[allow(rustc::untranslatable_diagnostic)] - // Don't know which of the two features to include in the - // error message, so I am arbitrarily picking one. - feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental") + // Emit yield_expr as the error, since that will be sufficient. You can think of it + // as coroutines and gen_blocks imply yield_expr. + feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental") .emit(); } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index c6b29fe36fd..0c46e0c0c22 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { assert_matches!( self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure )), "this needs to be modified if we're lowering non-async closures" diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 4b93b3414c7..b1d950b8d89 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -8,6 +8,8 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_local, path_std}; +/// Expands a `#[derive(PartialEq)]` attribute into an implementation for the +/// target item. pub(crate) fn expand_deriving_partial_eq( cx: &ExtCtxt<'_>, span: Span, @@ -16,62 +18,6 @@ pub(crate) fn expand_deriving_partial_eq( push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { - let base = true; - let expr = cs_fold( - true, // use foldl - cx, - span, - substr, - |cx, fold| match fold { - CsFold::Single(field) => { - let [other_expr] = &field.other_selflike_exprs[..] else { - cx.dcx() - .span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); - }; - - // We received arguments of type `&T`. Convert them to type `T` by stripping - // any leading `&`. This isn't necessary for type checking, but - // it results in better error messages if something goes wrong. - // - // Note: for arguments that look like `&{ x }`, which occur with packed - // structs, this would cause expressions like `{ self.x } == { other.x }`, - // which isn't valid Rust syntax. This wouldn't break compilation because these - // AST nodes are constructed within the compiler. But it would mean that code - // printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid - // syntax, which would be suboptimal. So we wrap these in parens, giving - // `({ self.x }) == ({ other.x })`, which is valid syntax. - let convert = |expr: &P<Expr>| { - if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = - &expr.kind - { - if let ExprKind::Block(..) = &inner.kind { - // `&{ x }` form: remove the `&`, add parens. - cx.expr_paren(field.span, inner.clone()) - } else { - // `&x` form: remove the `&`. - inner.clone() - } - } else { - expr.clone() - } - }; - cx.expr_binary( - field.span, - BinOpKind::Eq, - convert(&field.self_expr), - convert(other_expr), - ) - } - CsFold::Combine(span, expr1, expr2) => { - cx.expr_binary(span, BinOpKind::And, expr1, expr2) - } - CsFold::Fieldless => cx.expr_bool(span, base), - }, - ); - BlockOrExpr::new_expr(expr) - } - let structural_trait_def = TraitDef { span, path: path_std!(marker::StructuralPartialEq), @@ -97,7 +43,9 @@ pub(crate) fn expand_deriving_partial_eq( ret_ty: Path(path_local!(bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(Box::new(|a, b, c| cs_eq(a, b, c))), + combine_substructure: combine_substructure(Box::new(|a, b, c| { + BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) + })), }]; let trait_def = TraitDef { @@ -113,3 +61,156 @@ pub(crate) fn expand_deriving_partial_eq( }; trait_def.expand(cx, mitem, item, push) } + +/// Generates the equality expression for a struct or enum variant when deriving +/// `PartialEq`. +/// +/// This function generates an expression that checks if all fields of a struct +/// or enum variant are equal. +/// - Scalar fields are compared first for efficiency, followed by compound +/// fields. +/// - If there are no fields, returns `true` (fieldless types are always equal). +/// +/// Whether a field is considered "scalar" is determined by comparing the symbol +/// of its type to a set of known scalar type symbols (e.g., `i32`, `u8`, etc). +/// This check is based on the type's symbol. +/// +/// ### Example 1 +/// ``` +/// #[derive(PartialEq)] +/// struct i32; +/// +/// // Here, `field_2` is of type `i32`, but since it's a user-defined type (not +/// // the primitive), it will not be treated as scalar. The function will still +/// // check equality of `field_2` first because the symbol matches `i32`. +/// #[derive(PartialEq)] +/// struct Struct { +/// field_1: &'static str, +/// field_2: i32, +/// } +/// ``` +/// +/// ### Example 2 +/// ``` +/// mod ty { +/// pub type i32 = i32; +/// } +/// +/// // Here, `field_2` is of type `ty::i32`, which is a type alias for `i32`. +/// // However, the function will not reorder the fields because the symbol for +/// // `ty::i32` does not match the symbol for the primitive `i32` +/// // ("ty::i32" != "i32"). +/// #[derive(PartialEq)] +/// struct Struct { +/// field_1: &'static str, +/// field_2: ty::i32, +/// } +/// ``` +/// +/// For enums, the discriminant is compared first, then the rest of the fields. +/// +/// # Panics +/// +/// If called on static or all-fieldless enums/structs, which should not occur +/// during derive expansion. +fn get_substructure_equality_expr( + cx: &ExtCtxt<'_>, + span: Span, + substructure: &Substructure<'_>, +) -> P<Expr> { + use SubstructureFields::*; + + match substructure.fields { + EnumMatching(.., fields) | Struct(.., fields) => { + let combine = move |acc, field| { + let rhs = get_field_equality_expr(cx, field); + if let Some(lhs) = acc { + // Combine the previous comparison with the current field + // using logical AND. + return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)); + } + // Start the chain with the first field's comparison. + Some(rhs) + }; + + // First compare scalar fields, then compound fields, combining all + // with logical AND. + return fields + .iter() + .filter(|field| !field.maybe_scalar) + .fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine) + // If there are no fields, treat as always equal. + .unwrap_or_else(|| cx.expr_bool(span, true)); + } + EnumDiscr(disc, match_expr) => { + let lhs = get_field_equality_expr(cx, disc); + let Some(match_expr) = match_expr else { + return lhs; + }; + // Compare the discriminant first (cheaper), then the rest of the + // fields. + return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone()); + } + StaticEnum(..) => cx.dcx().span_bug( + span, + "unexpected static enum encountered during `derive(PartialEq)` expansion", + ), + StaticStruct(..) => cx.dcx().span_bug( + span, + "unexpected static struct encountered during `derive(PartialEq)` expansion", + ), + AllFieldlessEnum(..) => cx.dcx().span_bug( + span, + "unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion", + ), + } +} + +/// Generates an equality comparison expression for a single struct or enum +/// field. +/// +/// This function produces an AST expression that compares the `self` and +/// `other` values for a field using `==`. It removes any leading references +/// from both sides for readability. If the field is a block expression, it is +/// wrapped in parentheses to ensure valid syntax. +/// +/// # Panics +/// +/// Panics if there are not exactly two arguments to compare (should be `self` +/// and `other`). +fn get_field_equality_expr(cx: &ExtCtxt<'_>, field: &FieldInfo) -> P<Expr> { + let [rhs] = &field.other_selflike_exprs[..] else { + cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); + }; + + cx.expr_binary( + field.span, + BinOpKind::Eq, + wrap_block_expr(cx, peel_refs(&field.self_expr)), + wrap_block_expr(cx, peel_refs(rhs)), + ) +} + +/// Removes all leading immutable references from an expression. +/// +/// This is used to strip away any number of leading `&` from an expression +/// (e.g., `&&&T` becomes `T`). Only removes immutable references; mutable +/// references are preserved. +fn peel_refs(mut expr: &P<Expr>) -> P<Expr> { + while let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind { + expr = &inner; + } + expr.clone() +} + +/// Wraps a block expression in parentheses to ensure valid AST in macro +/// expansion output. +/// +/// If the given expression is a block, it is wrapped in parentheses; otherwise, +/// it is returned unchanged. +fn wrap_block_expr(cx: &ExtCtxt<'_>, expr: P<Expr>) -> P<Expr> { + if matches!(&expr.kind, ExprKind::Block(..)) { + return cx.expr_paren(expr.span, expr); + } + expr +} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f1bef526c10..6dd3adf750d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -284,6 +284,7 @@ pub(crate) struct FieldInfo { /// The expressions corresponding to references to this field in /// the other selflike arguments. pub other_selflike_exprs: Vec<P<Expr>>, + pub maybe_scalar: bool, } #[derive(Copy, Clone)] @@ -1220,7 +1221,8 @@ impl<'a> MethodDef<'a> { let self_expr = discr_exprs.remove(0); let other_selflike_exprs = discr_exprs; - let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; + let discr_field = + FieldInfo { span, name: None, self_expr, other_selflike_exprs, maybe_scalar: true }; let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args) .map(|(&ident, selflike_arg)| { @@ -1533,6 +1535,7 @@ impl<'a> TraitDef<'a> { name: struct_field.ident, self_expr, other_selflike_exprs, + maybe_scalar: struct_field.ty.peel_refs().kind.maybe_scalar(), } }) .collect() diff --git a/compiler/rustc_builtin_macros/src/iter.rs b/compiler/rustc_builtin_macros/src/iter.rs new file mode 100644 index 00000000000..7ad83903a1b --- /dev/null +++ b/compiler/rustc_builtin_macros/src/iter.rs @@ -0,0 +1,53 @@ +use rustc_ast::ptr::P; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::Span; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let closure = match parse_closure(cx, sp, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::expr(closure)) +} + +fn parse_closure<'a>( + cx: &mut ExtCtxt<'a>, + span: Span, + stream: TokenStream, +) -> PResult<'a, P<Expr>> { + let mut closure_parser = cx.new_parser_from_tts(stream); + + let coroutine_kind = Some(CoroutineKind::Gen { + span, + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + }); + + let mut closure = closure_parser.parse_expr()?; + match &mut closure.kind { + ast::ExprKind::Closure(c) => { + if let Some(kind) = c.coroutine_kind { + cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`"); + } + c.coroutine_kind = coroutine_kind; + if closure_parser.token != token::Eof { + closure_parser.unexpected()?; + } + Ok(closure) + } + _ => { + cx.dcx().span_err(closure.span, "`iter!` body must be a closure"); + Err(closure_parser.unexpected().unwrap_err()) + } + } +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 667d90429f2..aa52c3bd281 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -47,6 +47,7 @@ mod errors; mod format; mod format_foreign; mod global_allocator; +mod iter; mod log_syntax; mod pattern_type; mod source_util; @@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { include: source_util::expand_include, include_bytes: source_util::expand_include_bytes, include_str: source_util::expand_include_str, + iter: iter::expand, line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs index f2399768459..d9807155a3d 100644 --- a/compiler/rustc_codegen_cranelift/build_system/utils.rs +++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs @@ -213,11 +213,13 @@ pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) { if filename == "." || filename == ".." { continue; } + let src = from.join(&filename); + let dst = to.join(&filename); if entry.metadata().unwrap().is_dir() { - fs::create_dir(to.join(&filename)).unwrap(); - copy_dir_recursively(&from.join(&filename), &to.join(&filename)); + fs::create_dir(&dst).unwrap_or_else(|e| panic!("failed to create {dst:?}: {e}")); + copy_dir_recursively(&src, &dst); } else { - fs::copy(from.join(&filename), to.join(&filename)).unwrap(); + fs::copy(&src, &dst).unwrap_or_else(|e| panic!("failed to copy {src:?}->{dst:?}: {e}")); } } } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 5f7bf3821d7..fe5b220117f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -10,7 +10,7 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; -use rustc_abi::ExternAbi; +use rustc_abi::{CanonAbi, ExternAbi, X86Call}; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -19,7 +19,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::Session; use rustc_span::source_map::Spanned; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{FnAbi, PassMode}; use smallvec::SmallVec; use self::pass_mode::*; @@ -42,32 +42,27 @@ fn clif_sig_from_fn_abi<'tcx>( Signature { params, returns, call_conv } } -pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { +pub(crate) fn conv_to_call_conv( + sess: &Session, + c: CanonAbi, + default_call_conv: CallConv, +) -> CallConv { match c { - Conv::Rust | Conv::C => default_call_conv, - Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold, - Conv::X86_64SysV => CallConv::SystemV, - Conv::X86_64Win64 => CallConv::WindowsFastcall, - - // Should already get a back compat warning - Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => { - default_call_conv - } - - Conv::X86Intr | Conv::RiscvInterrupt { .. } => { - sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented")) + CanonAbi::Rust | CanonAbi::C => default_call_conv, + CanonAbi::RustCold => CallConv::Cold, + + CanonAbi::X86(x86_call) => match x86_call { + X86Call::SysV64 => CallConv::SystemV, + X86Call::Win64 => CallConv::WindowsFastcall, + // Should already get a back compat warning + _ => default_call_conv, + }, + + CanonAbi::Interrupt(_) | CanonAbi::Arm(_) => { + sess.dcx().fatal("call conv {c:?} is not yet implemented") } - - Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"), - Conv::CCmseNonSecureCall => { - sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); - } - Conv::CCmseNonSecureEntry => { - sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); - } - - Conv::Msp430Intr | Conv::GpuKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { - unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); + CanonAbi::GpuKernel => { + unreachable!("tried to use {c:?} call conv which only exists on an unsupported target") } } } @@ -610,7 +605,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( target: CallTarget, call_args: &mut Vec<Value>, ) { - if fn_abi.conv != Conv::C { + if fn_abi.conv != CanonAbi::C { fx.tcx.dcx().span_fatal( source_info.span, format!("Variadic call for non-C abi {:?}", fn_abi.conv), diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 0c499ba6237..3d0c258f576 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -1,7 +1,7 @@ #[cfg(feature = "master")] use gccjit::FnAttribute; use gccjit::{ToLValue, ToRValue, Type}; -use rustc_abi::{Reg, RegKind}; +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, Reg, RegKind, X86Call}; use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeCodegenMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -10,8 +10,6 @@ use rustc_middle::ty::layout::LayoutOf; #[cfg(feature = "master")] use rustc_session::config; use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode}; -#[cfg(feature = "master")] -use rustc_target::callconv::{Conv, RiscvInterruptKind}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -238,29 +236,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } #[cfg(feature = "master")] -pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> { +pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> { let attribute = match conv { - Conv::C | Conv::Rust => return None, - Conv::CCmseNonSecureCall => { - if arch == "arm" { - FnAttribute::ArmCmseNonsecureCall - } else { - return None; - } - } - Conv::CCmseNonSecureEntry => { - if arch == "arm" { - FnAttribute::ArmCmseNonsecureEntry - } else { - return None; - } - } - Conv::Cold => FnAttribute::Cold, - // NOTE: the preserve attributes are not yet implemented in GCC: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110899 - Conv::PreserveMost => return None, - Conv::PreserveAll => return None, - Conv::GpuKernel => { + CanonAbi::C | CanonAbi::Rust => return None, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, + ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, + ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), + }, + CanonAbi::RustCold => FnAttribute::Cold, + CanonAbi::GpuKernel => { if arch == "amdgpu" { FnAttribute::GcnAmdGpuHsaKernel } else if arch == "nvptx64" { @@ -270,26 +255,24 @@ pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute< } } // TODO(antoyo): check if those AVR attributes are mapped correctly. - Conv::AvrInterrupt => FnAttribute::AvrSignal, - Conv::AvrNonBlockingInterrupt => FnAttribute::AvrInterrupt, - Conv::ArmAapcs => FnAttribute::ArmPcs("aapcs"), - Conv::Msp430Intr => FnAttribute::Msp430Interrupt, - Conv::RiscvInterrupt { kind } => { - let kind = match kind { - RiscvInterruptKind::Machine => "machine", - RiscvInterruptKind::Supervisor => "supervisor", - }; - FnAttribute::RiscvInterrupt(kind) - } - Conv::X86Fastcall => FnAttribute::X86FastCall, - Conv::X86Intr => FnAttribute::X86Interrupt, - Conv::X86Stdcall => FnAttribute::X86Stdcall, - Conv::X86ThisCall => FnAttribute::X86ThisCall, - // NOTE: the vectorcall calling convention is not yet implemented in GCC: - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485 - Conv::X86VectorCall => return None, - Conv::X86_64SysV => FnAttribute::X86SysvAbi, - Conv::X86_64Win64 => FnAttribute::X86MsAbi, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => FnAttribute::AvrSignal, + InterruptKind::AvrNonBlocking => FnAttribute::AvrInterrupt, + InterruptKind::Msp430 => FnAttribute::Msp430Interrupt, + InterruptKind::RiscvMachine => FnAttribute::RiscvInterrupt("machine"), + InterruptKind::RiscvSupervisor => FnAttribute::RiscvInterrupt("supervisor"), + InterruptKind::X86 => FnAttribute::X86Interrupt, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => FnAttribute::X86FastCall, + X86Call::Stdcall => FnAttribute::X86Stdcall, + X86Call::Thiscall => FnAttribute::X86ThisCall, + // // NOTE: the vectorcall calling convention is not yet implemented in GCC: + // // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485 + X86Call::Vectorcall => return None, + X86Call::SysV64 => FnAttribute::X86SysvAbi, + X86Call::Win64 => FnAttribute::X86MsAbi, + }, }; Some(attribute) } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index e0597d0030d..3a265fbc64f 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -52,10 +52,6 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { fn clear_dbg_loc(&mut self) { self.location = None; } - - fn get_dbg_loc(&self) -> Option<Self::DILocation> { - self.location - } } /// Generate the `debug_context` in an MIR Body. diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 9b5b0fde6e2..eb4acd8ade9 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -3,11 +3,11 @@ //! 128-bit integers on 32-bit platforms and thus require to be handled manually. use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp}; -use rustc_abi::{Endian, ExternAbi}; +use rustc_abi::{CanonAbi, Endian, ExternAbi}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp}; use rustc_middle::ty::{self, Ty}; -use rustc_target::callconv::{ArgAbi, ArgAttributes, Conv, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode}; use crate::builder::{Builder, ToGccComp}; use crate::common::{SignType, TypeReflection}; @@ -397,7 +397,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ret: arg_abi, c_variadic: false, fixed_count: 3, - conv: Conv::C, + conv: CanonAbi::C, can_unwind: false, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 73be25ba92b..9e05b8f23aa 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -524,11 +524,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc cond } - fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value { - // Unsupported. - self.context.new_rvalue_from_int(self.int_type, 0) - } - fn type_checked_load( &mut self, _llvtable: Self::Value, diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index c87e70864e5..119cd634f98 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -2,7 +2,10 @@ use std::borrow::Borrow; use std::cmp; use libc::c_uint; -use rustc_abi::{BackendRepr, HasDataLayout, Primitive, Reg, RegKind, Size}; +use rustc_abi::{ + ArmCall, BackendRepr, CanonAbi, HasDataLayout, InterruptKind, Primitive, Reg, RegKind, Size, + X86Call, +}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; @@ -12,7 +15,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_middle::{bug, ty}; use rustc_session::config; use rustc_target::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, Conv, FnAbi, PassMode, + ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, }; use rustc_target::spec::SanitizerSet; use smallvec::SmallVec; @@ -409,11 +412,17 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if !self.can_unwind { func_attrs.push(llvm::AttributeKind::NoUnwind.create_attr(cx.llcx)); } - if let Conv::RiscvInterrupt { kind } = self.conv { - func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str())); - } - if let Conv::CCmseNonSecureEntry = self.conv { - func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + match self.conv { + CanonAbi::Interrupt(InterruptKind::RiscvMachine) => { + func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "machine")) + } + CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) => { + func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", "supervisor")) + } + CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) => { + func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + } + _ => (), } attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs }); @@ -600,7 +609,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llvm::SetInstructionCallConv(callsite, cconv); } - if self.conv == Conv::CCmseNonSecureCall { + if self.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) { // This will probably get ignored on all targets but those supporting the TrustZone-M // extension (thumbv8m targets). let cmse_nonsecure_call = llvm::CreateAttrString(bx.cx.llcx, "cmse_nonsecure_call"); @@ -636,17 +645,11 @@ impl AbiBuilderMethods for Builder<'_, '_, '_> { } impl llvm::CallConv { - pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self { + pub(crate) fn from_conv(conv: CanonAbi, arch: &str) -> Self { match conv { - Conv::C - | Conv::Rust - | Conv::CCmseNonSecureCall - | Conv::CCmseNonSecureEntry - | Conv::RiscvInterrupt { .. } => llvm::CCallConv, - Conv::Cold => llvm::ColdCallConv, - Conv::PreserveMost => llvm::PreserveMost, - Conv::PreserveAll => llvm::PreserveAll, - Conv::GpuKernel => { + CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, + CanonAbi::RustCold => llvm::PreserveMost, + CanonAbi::GpuKernel => { if arch == "amdgpu" { llvm::AmdgpuKernel } else if arch == "nvptx64" { @@ -655,17 +658,25 @@ impl llvm::CallConv { panic!("Architecture {arch} does not support GpuKernel calling convention"); } } - Conv::AvrInterrupt => llvm::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, - Conv::ArmAapcs => llvm::ArmAapcsCallConv, - Conv::Msp430Intr => llvm::Msp430Intr, - Conv::X86Fastcall => llvm::X86FastcallCallConv, - Conv::X86Intr => llvm::X86_Intr, - Conv::X86Stdcall => llvm::X86StdcallCallConv, - Conv::X86ThisCall => llvm::X86_ThisCall, - Conv::X86VectorCall => llvm::X86_VectorCall, - Conv::X86_64SysV => llvm::X86_64_SysV, - Conv::X86_64Win64 => llvm::X86_64_Win64, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => llvm::AvrInterrupt, + InterruptKind::AvrNonBlocking => llvm::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => llvm::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => llvm::CCallConv, + InterruptKind::X86 => llvm::X86_Intr, + }, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => llvm::ArmAapcsCallConv, + ArmCall::CCmseNonSecureCall | ArmCall::CCmseNonSecureEntry => llvm::CCallConv, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => llvm::X86FastcallCallConv, + X86Call::Stdcall => llvm::X86StdcallCallConv, + X86Call::SysV64 => llvm::X86_64_SysV, + X86Call::Thiscall => llvm::X86_ThisCall, + X86Call::Vectorcall => llvm::X86_VectorCall, + X86Call::Win64 => llvm::X86_64_Win64, + }, } } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 167678c2ff1..ec006b59192 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1815,8 +1815,11 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); let dbg_loc = self.get_dbg_loc(); - // Test whether the function pointer is associated with the type identifier. - let cond = self.type_test(llfn, typeid_metadata); + // Test whether the function pointer is associated with the type identifier using the + // llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces + // calls to this intrinsic with code to test type membership. + let typeid = self.get_metadata_value(typeid_metadata); + let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]); let bb_pass = self.append_sibling_block("type_test.pass"); let bb_fail = self.append_sibling_block("type_test.fail"); self.cond_br(cond, bb_pass, bb_fail); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index c5085927923..5ca2505cec4 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -147,6 +147,12 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { } } +impl<'ll> Builder<'_, 'll, '_> { + pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> { + unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) } + } +} + impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // FIXME(eddyb) find a common convention for all of the debuginfo-related // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). @@ -209,10 +215,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { } } - fn get_dbg_loc(&self) -> Option<&'ll DILocation> { - unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) } - } - fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { gdb::insert_reference_to_gdb_debug_scripts_section_global(self) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 989752eb78e..10697b9a71f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -636,13 +636,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { - // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time - // optimization pass replaces calls to this intrinsic with code to test type membership. - let typeid = self.get_metadata_value(typeid); - self.call_intrinsic("llvm.type.test", &[pointer, typeid]) - } - fn type_checked_load( &mut self, llvtable: &'ll Value, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 8f57f0983ab..9718c95f38a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -282,6 +282,14 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea } // Filter out features that are not supported by the current LLVM version ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, + ( + "s390x", + "message-security-assist-extension12" + | "concurrent-functions" + | "miscellaneous-extensions-4" + | "vector-enhancements-3" + | "vector-packed-decimal-enhancement-3", + ) if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index e26f999773d..92b9b6e132e 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,5 +1,6 @@ use std::collections::hash_map::Entry::*; +use rustc_abi::{CanonAbi, X86Call}; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; use rustc_data_structures::unord::UnordMap; use rustc_hir::def::DefKind; @@ -14,7 +15,6 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OomStrategy}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::callconv::Conv; use rustc_target::spec::{SanitizerSet, TlsModel}; use tracing::debug; @@ -652,7 +652,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( fn calling_convention_for_symbol<'tcx>( tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, -) -> (Conv, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) { +) -> (CanonAbi, &'tcx [rustc_target::callconv::ArgAbi<'tcx, Ty<'tcx>>]) { let instance = match symbol { ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) if tcx.is_static(def_id) => @@ -683,7 +683,7 @@ fn calling_convention_for_symbol<'tcx>( }) .map(|fnabi| (fnabi.conv, &fnabi.args[..])) // FIXME(workingjubilee): why don't we know the convention here? - .unwrap_or((Conv::Rust, &[])) + .unwrap_or((CanonAbi::Rust, &[])) } /// This is the symbol name of the given instance as seen by the linker. @@ -717,14 +717,14 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>( _ => return undecorated, }; - let (conv, args) = calling_convention_for_symbol(tcx, symbol); + let (callconv, args) = calling_convention_for_symbol(tcx, symbol); // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 - let (prefix, suffix) = match conv { - Conv::X86Fastcall => ("@", "@"), - Conv::X86Stdcall => ("_", "@"), - Conv::X86VectorCall => ("", "@@"), + let (prefix, suffix) = match callconv { + CanonAbi::X86(X86Call::Fastcall) => ("@", "@"), + CanonAbi::X86(X86Call::Stdcall) => ("_", "@"), + CanonAbi::X86(X86Call::Vectorcall) => ("", "@@"), _ => { if let Some(prefix) = prefix { undecorated.insert(0, prefix); @@ -758,9 +758,9 @@ pub(crate) fn extend_exported_symbols<'tcx>( symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, ) { - let (conv, _) = calling_convention_for_symbol(tcx, symbol); + let (callconv, _) = calling_convention_for_symbol(tcx, symbol); - if conv != Conv::GpuKernel || tcx.sess.target.os != "amdhsa" { + if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != "amdhsa" { return; } diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index 30d77c206a5..b9d4950e0ad 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -81,7 +81,6 @@ pub trait DebugInfoBuilderMethods: BackendTypes { ); fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation); fn clear_dbg_loc(&mut self); - fn get_dbg_loc(&self) -> Option<Self::DILocation>; fn insert_reference_to_gdb_debug_scripts_section_global(&mut self); fn set_var_name(&mut self, value: Self::Value, name: &str); } diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index a07c569a032..7d0c6be4c65 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -22,8 +22,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Trait method used to test whether a given pointer is associated with a type identifier. - fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value; /// Trait method used to load a function while testing if it is associated with a type /// identifier. fn type_checked_load( diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 7d4afc9d3d9..5bce6fb7ab2 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -89,9 +89,9 @@ const_eval_dyn_call_not_a_method = `dyn` call trying to call something that is not a method const_eval_error = {$error_kind -> - [static] could not evaluate static initializer - [const] evaluation of constant value failed - [const_with_path] evaluation of `{$instance}` failed + [static] evaluation of static initializer failed here + [const] evaluation of constant value failed here + [const_with_path] evaluation of `{$instance}` failed here *[other] {""} } @@ -118,7 +118,7 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here const_eval_incompatible_calling_conventions = - calling a function with calling convention {$callee_conv} using calling convention {$caller_conv} + calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" const_eval_incompatible_return_types = calling a function with return type {$callee_ty} passing return place of type {$caller_ty} diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index b67a3ce03a9..6167f8cd4b5 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -589,12 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() - && let Some( - coroutine_kind @ hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - _, - ), - ) = self.tcx.coroutine_kind(def_id) + && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id) { self.check_op(ops::Coroutine(coroutine_kind)); } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 177ba56b165..d701646719a 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -486,24 +486,25 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { pub(crate) struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) = self.0 - { - Status::Unstable { + match self.0 { + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) + // FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a + // different feature. + | hir::CoroutineKind::Coroutine(_) => Status::Unstable { gate: sym::const_async_blocks, gate_already_checked: false, safe_to_expose_on_stable: false, is_function_call: false, - } - } else { - Status::Forbidden + }, + _ => Status::Forbidden, } } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); + let msg = format!("{} are not allowed in {}s", self.0.to_plural_string(), ccx.const_kind()); if let Status::Unstable { gate, .. } = self.status_in_item(ccx) { ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate) } else { diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index ffb32fa41eb..08fc03d9c46 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; +use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; @@ -131,10 +131,10 @@ pub fn get_span_and_frames<'tcx>( /// Create a diagnostic for a const eval error. /// -/// This will use the `mk` function for creating the error which will get passed labels according to -/// the `InterpError` and the span and a stacktrace of current execution according to -/// `get_span_and_frames`. -pub(super) fn report<'tcx, C, F, E>( +/// This will use the `mk` function for adding more information to the error. +/// You can use it to add a stacktrace of current execution according to +/// `get_span_and_frames` or just give context on where the const eval error happened. +pub(super) fn report<'tcx, C, F>( tcx: TyCtxt<'tcx>, error: InterpErrorKind<'tcx>, span: Span, @@ -143,8 +143,7 @@ pub(super) fn report<'tcx, C, F, E>( ) -> ErrorHandled where C: FnOnce() -> (Span, Vec<FrameNote>), - F: FnOnce(Span, Vec<FrameNote>) -> E, - E: Diagnostic<'tcx>, + F: FnOnce(&mut Diag<'_>, Span, Vec<FrameNote>), { // Special handling for certain errors match error { @@ -163,8 +162,7 @@ where _ => { let (our_span, frames) = get_span_and_frames(); let span = span.substitute_dummy(our_span); - let err = mk(span, frames); - let mut err = tcx.dcx().create_err(err); + let mut err = tcx.dcx().struct_span_err(our_span, error.diagnostic_message()); // We allow invalid programs in infallible promoteds since invalid layouts can occur // anyway (e.g. due to size overflow). And we allow OOM as that can happen any time. let allowed_in_infallible = matches!( @@ -172,11 +170,9 @@ where InterpErrorKind::ResourceExhaustion(_) | InterpErrorKind::InvalidProgram(_) ); - let msg = error.diagnostic_message(); error.add_args(&mut err); - // Use *our* span to label the interp error - err.span_label(our_span, msg); + mk(&mut err, span, frames); let g = err.emit(); let reported = if allowed_in_infallible { ReportedErrorInfo::allowed_in_infallible(g) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a79ba6a6342..01625b91353 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,6 +2,7 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; use rustc_abi::{self as abi, BackendRepr}; +use rustc_errors::E0080; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; @@ -290,12 +291,18 @@ pub fn eval_to_const_value_raw_provider<'tcx>( |error| { let span = tcx.def_span(def_id); + // FIXME(oli-obk): why don't we have any tests for this code path? super::report( tcx, error.into_kind(), span, || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, + |diag, span, _| { + diag.span_label( + span, + crate::fluent_generated::const_eval_nullary_intrinsic_fail, + ); + }, ) }, ); @@ -443,11 +450,15 @@ fn report_eval_error<'tcx>( error, DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), - |span, frames| errors::ConstEvalError { - span, - error_kind: kind, - instance, - frame_notes: frames, + |diag, span, frames| { + // FIXME(oli-obk): figure out how to use structured diagnostics again. + diag.code(E0080); + diag.span_label(span, crate::fluent_generated::const_eval_error); + diag.arg("instance", instance); + diag.arg("error_kind", kind); + for frame in frames { + diag.subdiagnostic(frame); + } }, ) } @@ -477,6 +488,15 @@ fn report_validation_error<'tcx>( error, DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), - move |span, frames| errors::ValidationFailure { span, ub_note: (), frames, raw_bytes }, + move |diag, span, frames| { + // FIXME(oli-obk): figure out how to use structured diagnostics again. + diag.code(E0080); + diag.span_label(span, crate::fluent_generated::const_eval_validation_failure); + diag.note(crate::fluent_generated::const_eval_validation_failure_note); + for frame in frames { + diag.subdiagnostic(frame); + } + diag.subdiagnostic(raw_bytes); + }, ) } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 7c35e47bbf8..037cbf777e7 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -439,38 +439,6 @@ pub struct LiveDrop<'tcx> { pub dropped_at: Span, } -#[derive(Diagnostic)] -#[diag(const_eval_error, code = E0080)] -pub struct ConstEvalError { - #[primary_span] - pub span: Span, - /// One of "const", "const_with_path", and "static" - pub error_kind: &'static str, - pub instance: String, - #[subdiagnostic] - pub frame_notes: Vec<FrameNote>, -} - -#[derive(Diagnostic)] -#[diag(const_eval_nullary_intrinsic_fail)] -pub struct NullaryIntrinsicError { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(const_eval_validation_failure, code = E0080)] -pub struct ValidationFailure { - #[primary_span] - pub span: Span, - #[note(const_eval_validation_failure_note)] - pub ub_note: (), - #[subdiagnostic] - pub frames: Vec<FrameNote>, - #[subdiagnostic] - pub raw_bytes: RawBytesNote, -} - pub trait ReportErrorExt { /// Returns the diagnostic message for this error. fn diagnostic_message(&self) -> DiagMessage; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4f05e1c816c..433d5f98829 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2061,12 +2061,19 @@ impl CoroutineKind { CoroutineKind::Coroutine(mov) => mov, } } -} -impl CoroutineKind { pub fn is_fn_like(self) -> bool { matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn)) } + + pub fn to_plural_string(&self) -> String { + match self { + CoroutineKind::Desugared(d, CoroutineSource::Fn) => format!("{d:#}fn bodies"), + CoroutineKind::Desugared(d, CoroutineSource::Block) => format!("{d:#}blocks"), + CoroutineKind::Desugared(d, CoroutineSource::Closure) => format!("{d:#}closure bodies"), + CoroutineKind::Coroutine(_) => "coroutines".to_string(), + } + } } impl fmt::Display for CoroutineKind { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b6ebd61301c..b9932a7334e 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -527,13 +527,15 @@ pub trait VisitorExt<'v>: Visitor<'v> { impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {} pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> V::Result { - try_visit!(visitor.visit_id(param.hir_id)); - visitor.visit_pat(param.pat) + let Param { hir_id, pat, ty_span: _, span: _ } = param; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_pat(pat) } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { + let Item { owner_id: _, kind, span: _, vis_span: _ } = item; try_visit!(visitor.visit_id(item.hir_id())); - match item.kind { + match *kind { ItemKind::ExternCrate(orig_name, ident) => { visit_opt!(visitor, visit_name, orig_name); try_visit!(visitor.visit_ident(ident)); @@ -631,8 +633,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &Body<'v>) -> V::Result { - walk_list!(visitor, visit_param, body.params); - visitor.visit_expr(body.value) + let Body { params, value } = body; + walk_list!(visitor, visit_param, *params); + visitor.visit_expr(*value) } pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Result { @@ -640,7 +643,8 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul } pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result { - walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); + let Mod { spans: _, item_ids } = module; + walk_list!(visitor, visit_nested_item, item_ids.iter().copied()); V::Result::output() } @@ -648,10 +652,11 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item: &'v ForeignItem<'v>, ) -> V::Result { + let ForeignItem { ident, kind, owner_id: _, span: _, vis_span: _ } = foreign_item; try_visit!(visitor.visit_id(foreign_item.hir_id())); - try_visit!(visitor.visit_ident(foreign_item.ident)); + try_visit!(visitor.visit_ident(*ident)); - match foreign_item.kind { + match *kind { ForeignItemKind::Fn(ref sig, param_idents, ref generics) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(sig.decl)); @@ -670,24 +675,27 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result { // Intentionally visiting the expr first - the initialization expr // dominates the local's definition. - visit_opt!(visitor, visit_expr, local.init); - try_visit!(visitor.visit_id(local.hir_id)); - try_visit!(visitor.visit_pat(local.pat)); - visit_opt!(visitor, visit_block, local.els); - visit_opt!(visitor, visit_ty_unambig, local.ty); + let LetStmt { super_: _, pat, ty, init, els, hir_id, span: _, source: _ } = local; + visit_opt!(visitor, visit_expr, *init); + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_pat(*pat)); + visit_opt!(visitor, visit_block, *els); + visit_opt!(visitor, visit_ty_unambig, *ty); V::Result::output() } pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) -> V::Result { - try_visit!(visitor.visit_id(block.hir_id)); - walk_list!(visitor, visit_stmt, block.stmts); - visit_opt!(visitor, visit_expr, block.expr); + let Block { stmts, expr, hir_id, rules: _, span: _, targeted_by_break: _ } = block; + try_visit!(visitor.visit_id(*hir_id)); + walk_list!(visitor, visit_stmt, *stmts); + visit_opt!(visitor, visit_expr, *expr); V::Result::output() } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) -> V::Result { - try_visit!(visitor.visit_id(statement.hir_id)); - match statement.kind { + let Stmt { kind, hir_id, span: _ } = statement; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { StmtKind::Let(ref local) => visitor.visit_local(local), StmtKind::Item(item) => visitor.visit_nested_item(item), StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => { @@ -697,15 +705,17 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) - } pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Result { - try_visit!(visitor.visit_id(arm.hir_id)); - try_visit!(visitor.visit_pat(arm.pat)); - visit_opt!(visitor, visit_expr, arm.guard); - visitor.visit_expr(arm.body) + let Arm { hir_id, span: _, pat, guard, body } = arm; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_pat(*pat)); + visit_opt!(visitor, visit_expr, *guard); + visitor.visit_expr(*body) } pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result { - try_visit!(visitor.visit_id(pattern.hir_id)); - match pattern.kind { + let TyPat { kind, hir_id, span: _ } = pattern; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { TyPatKind::Range(lower_bound, upper_bound) => { try_visit!(visitor.visit_const_arg_unambig(lower_bound)); try_visit!(visitor.visit_const_arg_unambig(upper_bound)); @@ -717,14 +727,15 @@ pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) } pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V::Result { - try_visit!(visitor.visit_id(pattern.hir_id)); - match pattern.kind { + let Pat { hir_id, kind, span, default_binding_modes: _ } = pattern; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { PatKind::TupleStruct(ref qpath, children, _) => { - try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_pat, children); } PatKind::Struct(ref qpath, fields, _) => { - try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_pat_field, fields); } PatKind::Or(pats) => walk_list!(visitor, visit_pat, pats), @@ -760,36 +771,41 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V: } pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'v>) -> V::Result { - try_visit!(visitor.visit_id(field.hir_id)); - try_visit!(visitor.visit_ident(field.ident)); - visitor.visit_pat(field.pat) + let PatField { hir_id, ident, pat, is_shorthand: _, span: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + visitor.visit_pat(*pat) } pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result { - try_visit!(visitor.visit_id(expr.hir_id)); - match &expr.kind { - PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated), + let PatExpr { hir_id, span, kind } = expr; + try_visit!(visitor.visit_id(*hir_id)); + match kind { + PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, lit, *negated), PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), - PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span), + PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span), } } pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) -> V::Result { - try_visit!(visitor.visit_id(constant.hir_id)); - visitor.visit_nested_body(constant.body) + let AnonConst { hir_id, def_id: _, body, span: _ } = constant; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_nested_body(*body) } pub fn walk_inline_const<'v, V: Visitor<'v>>( visitor: &mut V, constant: &'v ConstBlock, ) -> V::Result { - try_visit!(visitor.visit_id(constant.hir_id)); - visitor.visit_nested_body(constant.body) + let ConstBlock { hir_id, def_id: _, body } = constant; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_nested_body(*body) } pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { - try_visit!(visitor.visit_id(expression.hir_id)); - match expression.kind { + let Expr { hir_id, kind, span } = expression; + try_visit!(visitor.visit_id(*hir_id)); + match *kind { ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } @@ -801,7 +817,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_const_arg_unambig(count)); } ExprKind::Struct(ref qpath, fields, ref optional_base) => { - try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); walk_list!(visitor, visit_expr_field, fields); match optional_base { StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)), @@ -869,7 +885,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); - try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, def_id)); + try_visit!(visitor.visit_fn(FnKind::Closure, fn_decl, body, *span, def_id)); } ExprKind::Block(ref block, ref opt_label) => { visit_opt!(visitor, visit_label, opt_label); @@ -892,7 +908,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(index_expression)); } ExprKind::Path(ref qpath) => { - try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span)); + try_visit!(visitor.visit_qpath(qpath, *hir_id, *span)); } ExprKind::Break(ref destination, ref opt_expr) => { visit_opt!(visitor, visit_label, &destination.label); @@ -906,7 +922,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) } ExprKind::Become(ref expr) => try_visit!(visitor.visit_expr(expr)), ExprKind::InlineAsm(ref asm) => { - try_visit!(visitor.visit_inline_asm(asm, expression.hir_id)); + try_visit!(visitor.visit_inline_asm(asm, *hir_id)); } ExprKind::OffsetOf(ref container, ref fields) => { try_visit!(visitor.visit_ty_unambig(container)); @@ -919,16 +935,17 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(expr)); visit_opt!(visitor, visit_ty_unambig, ty); } - ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)), + ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(*hir_id, lit, false)), ExprKind::Err(_) => {} } V::Result::output() } pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) -> V::Result { - try_visit!(visitor.visit_id(field.hir_id)); - try_visit!(visitor.visit_ident(field.ident)); - visitor.visit_expr(field.expr) + let ExprField { hir_id, ident, expr, span: _, is_shorthand: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + visitor.visit_expr(*expr) } /// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that /// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited @@ -946,7 +963,10 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), GenericArg::Type(ty) => visitor.visit_ty(ty), GenericArg::Const(ct) => visitor.visit_const_arg(ct), - GenericArg::Infer(inf) => visitor.visit_infer(inf.hir_id, inf.span, InferKind::Ambig(inf)), + GenericArg::Infer(inf) => { + let InferArg { hir_id, span } = inf; + visitor.visit_infer(*hir_id, *span, InferKind::Ambig(inf)) + } } } @@ -954,16 +974,18 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> match typ.try_as_ambig_ty() { Some(ambig_ty) => visitor.visit_ty(ambig_ty), None => { - try_visit!(visitor.visit_id(typ.hir_id)); - visitor.visit_infer(typ.hir_id, typ.span, InferKind::Ty(typ)) + let Ty { hir_id, span, kind: _ } = typ; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ)) } } } pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -> V::Result { - try_visit!(visitor.visit_id(typ.hir_id)); + let Ty { hir_id, span: _, kind } = typ; + try_visit!(visitor.visit_id(*hir_id)); - match typ.kind { + match *kind { TyKind::Slice(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)), TyKind::Ptr(ref mutable_type) => try_visit!(visitor.visit_ty_unambig(mutable_type.ty)), TyKind::Ref(ref lifetime, ref mutable_type) => { @@ -1018,8 +1040,9 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( match const_arg.try_as_ambig_ct() { Some(ambig_ct) => visitor.visit_const_arg(ambig_ct), None => { - try_visit!(visitor.visit_id(const_arg.hir_id)); - visitor.visit_infer(const_arg.hir_id, const_arg.span(), InferKind::Const(const_arg)) + let ConstArg { hir_id, kind: _ } = const_arg; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg)) } } } @@ -1028,9 +1051,10 @@ pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>( visitor: &mut V, const_arg: &'v ConstArg<'v, AmbigArg>, ) -> V::Result { - try_visit!(visitor.visit_id(const_arg.hir_id)); - match &const_arg.kind { - ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()), + let ConstArg { hir_id, kind } = const_arg; + try_visit!(visitor.visit_id(*hir_id)); + match kind { + ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), } } @@ -1039,12 +1063,22 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( visitor: &mut V, param: &'v GenericParam<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(param.hir_id)); - match param.name { + let GenericParam { + hir_id, + def_id: _, + name, + span: _, + pure_wrt_drop: _, + kind, + colon_span: _, + source: _, + } = param; + try_visit!(visitor.visit_id(*hir_id)); + match *name { ParamName::Plain(ident) | ParamName::Error(ident) => try_visit!(visitor.visit_ident(ident)), ParamName::Fresh => {} } - match param.kind { + match *kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => { visit_opt!(visitor, visit_ty_unambig, default) @@ -1052,7 +1086,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { try_visit!(visitor.visit_ty_unambig(ty)); if let Some(default) = default { - try_visit!(visitor.visit_const_param_default(param.hir_id, default)); + try_visit!(visitor.visit_const_param_default(*hir_id, default)); } } } @@ -1067,8 +1101,15 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>( } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result { - walk_list!(visitor, visit_generic_param, generics.params); - walk_list!(visitor, visit_where_predicate, generics.predicates); + let &Generics { + params, + predicates, + has_where_clause_predicates: _, + where_clause_span: _, + span: _, + } = generics; + walk_list!(visitor, visit_generic_param, params); + walk_list!(visitor, visit_where_predicate, predicates); V::Result::output() } @@ -1109,8 +1150,10 @@ pub fn walk_fn_decl<'v, V: Visitor<'v>>( visitor: &mut V, function_declaration: &'v FnDecl<'v>, ) -> V::Result { - walk_list!(visitor, visit_ty_unambig, function_declaration.inputs); - visitor.visit_fn_ret_ty(&function_declaration.output) + let FnDecl { inputs, output, c_variadic: _, implicit_self: _, lifetime_elision_allowed: _ } = + function_declaration; + walk_list!(visitor, visit_ty_unambig, *inputs); + visitor.visit_fn_ret_ty(output) } pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) -> V::Result { @@ -1264,8 +1307,9 @@ pub fn walk_trait_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_ref: &'v TraitRef<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(trait_ref.hir_ref_id)); - visitor.visit_path(trait_ref.path, trait_ref.hir_ref_id) + let TraitRef { hir_ref_id, path } = trait_ref; + try_visit!(visitor.visit_id(*hir_ref_id)); + visitor.visit_path(*path, *hir_ref_id) } pub fn walk_param_bound<'v, V: Visitor<'v>>( @@ -1288,7 +1332,10 @@ pub fn walk_precise_capturing_arg<'v, V: Visitor<'v>>( ) -> V::Result { match *arg { PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt), - PreciseCapturingArg::Param(param) => visitor.visit_id(param.hir_id), + PreciseCapturingArg::Param(param) => { + let PreciseCapturingNonLifetimeArg { hir_id, ident: _, res: _ } = param; + visitor.visit_id(hir_id) + } } } @@ -1296,8 +1343,9 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>, ) -> V::Result { - walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params); - visitor.visit_trait_ref(&trait_ref.trait_ref) + let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref; + walk_list!(visitor, visit_generic_param, *bound_generic_params); + visitor.visit_trait_ref(trait_ref) } pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result { @@ -1330,29 +1378,34 @@ pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, ) -> V::Result { - walk_list!(visitor, visit_variant, enum_definition.variants); + let EnumDef { variants } = enum_definition; + walk_list!(visitor, visit_variant, *variants); V::Result::output() } pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) -> V::Result { - try_visit!(visitor.visit_ident(variant.ident)); - try_visit!(visitor.visit_id(variant.hir_id)); - try_visit!(visitor.visit_variant_data(&variant.data)); - visit_opt!(visitor, visit_anon_const, &variant.disr_expr); + let Variant { ident, hir_id, def_id: _, data, disr_expr, span: _ } = variant; + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_variant_data(data)); + visit_opt!(visitor, visit_anon_const, disr_expr); V::Result::output() } pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) -> V::Result { - visitor.visit_ident(label.ident) + let Label { ident } = label; + visitor.visit_ident(*ident) } pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) -> V::Result { - visitor.visit_id(inf.hir_id) + let InferArg { hir_id, span: _ } = inf; + visitor.visit_id(*hir_id) } pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) -> V::Result { - try_visit!(visitor.visit_id(lifetime.hir_id)); - visitor.visit_ident(lifetime.ident) + let Lifetime { hir_id, ident, kind: _, source: _, syntax: _ } = lifetime; + try_visit!(visitor.visit_id(*hir_id)); + visitor.visit_ident(*ident) } pub fn walk_qpath<'v, V: Visitor<'v>>( @@ -1374,7 +1427,8 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( } pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &Path<'v>) -> V::Result { - walk_list!(visitor, visit_path_segment, path.segments); + let Path { segments, span: _, res: _ } = path; + walk_list!(visitor, visit_path_segment, *segments); V::Result::output() } @@ -1382,9 +1436,10 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>( visitor: &mut V, segment: &'v PathSegment<'v>, ) -> V::Result { - try_visit!(visitor.visit_ident(segment.ident)); - try_visit!(visitor.visit_id(segment.hir_id)); - visit_opt!(visitor, visit_generic_args, segment.args); + let PathSegment { ident, hir_id, res: _, args, infer_args: _ } = segment; + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_id(*hir_id)); + visit_opt!(visitor, visit_generic_args, *args); V::Result::output() } @@ -1392,8 +1447,9 @@ pub fn walk_generic_args<'v, V: Visitor<'v>>( visitor: &mut V, generic_args: &'v GenericArgs<'v>, ) -> V::Result { - walk_list!(visitor, visit_generic_arg, generic_args.args); - walk_list!(visitor, visit_assoc_item_constraint, generic_args.constraints); + let GenericArgs { args, constraints, parenthesized: _, span_ext: _ } = generic_args; + walk_list!(visitor, visit_generic_arg, *args); + walk_list!(visitor, visit_assoc_item_constraint, *constraints); V::Result::output() } @@ -1401,9 +1457,10 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>( visitor: &mut V, constraint: &'v AssocItemConstraint<'v>, ) -> V::Result { - try_visit!(visitor.visit_id(constraint.hir_id)); - try_visit!(visitor.visit_ident(constraint.ident)); - try_visit!(visitor.visit_generic_args(constraint.gen_args)); + let AssocItemConstraint { hir_id, ident, gen_args, kind: _, span: _ } = constraint; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + try_visit!(visitor.visit_generic_args(*gen_args)); match constraint.kind { AssocItemConstraintKind::Equality { ref term } => match term { Term::Ty(ty) => try_visit!(visitor.visit_ty_unambig(ty)), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b764b714fe1..3e872607e31 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{AmbigArg, ItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -2402,8 +2402,8 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { } } -fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { - let items = tcx.hir_module_items(module); +fn check_type_wf(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { + let items = tcx.hir_crate_items(()); let res = items .par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)) .and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) @@ -2412,9 +2412,8 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)), ) .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item))); - if module == LocalModDefId::CRATE_DEF_ID { - super::entry::check_for_entry_fn(tcx); - } + super::entry::check_for_entry_fn(tcx); + res } @@ -2552,5 +2551,5 @@ struct RedundantLifetimeArgsLint<'tcx> { } pub fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; + *providers = Providers { check_type_wf, check_well_formed, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a64c24f5455..f255817bffc 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -182,9 +182,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { // what we are intending to discard, to help future type-based refactoring. type R = Result<(), ErrorGuaranteed>; - tcx.par_hir_for_each_module(|module| { - let _: R = tcx.ensure_ok().check_mod_type_wf(module); - }); + let _: R = tcx.ensure_ok().check_type_wf(()); for &trait_def_id in tcx.all_local_trait_impls(()).keys() { let _: R = tcx.ensure_ok().coherent_trait(trait_def_id); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index b1cb3ef4d79..cd3746be1d1 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -204,14 +204,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } hir::ClosureKind::CoroutineClosure(kind) => { - // async closures always return the type ascribed after the `->` (if present), - // and yield `()`. let (bound_return_ty, bound_yield_ty) = match kind { + hir::CoroutineDesugaring::Gen => { + // `iter!` closures always return unit and yield the `Iterator::Item` type + // that we have to infer. + (tcx.types.unit, self.infcx.next_ty_var(expr_span)) + } hir::CoroutineDesugaring::Async => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. (bound_sig.skip_binder().output(), tcx.types.unit) } - hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => { - todo!("`gen` and `async gen` closures not supported yet") + hir::CoroutineDesugaring::AsyncGen => { + todo!("`async gen` closures not supported yet") } }; // Compute all of the variables that will be used to populate the coroutine. @@ -465,7 +470,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(trait_def_id) = trait_def_id { let found_kind = match closure_kind { - hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id), + hir::ClosureKind::Closure + // FIXME(iter_macro): Someday we'll probably want iterator closures instead of + // just using Fn* for iterators. + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => { + self.tcx.fn_trait_kind_from_def_id(trait_def_id) + } hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self .tcx .async_fn_trait_kind_from_def_id(trait_def_id) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 07934389158..a4885aabe1f 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -234,6 +234,32 @@ impl<T: Idx> DenseBitSet<T> { self.clear_excess_bits(); } + /// Checks whether any bit in the given range is a 1. + #[inline] + pub fn contains_any(&self, elems: impl RangeBounds<T>) -> bool { + let Some((start, end)) = inclusive_start_end(elems, self.domain_size) else { + return false; + }; + let (start_word_index, start_mask) = word_index_and_mask(start); + let (end_word_index, end_mask) = word_index_and_mask(end); + + if start_word_index == end_word_index { + self.words[start_word_index] & (end_mask | (end_mask - start_mask)) != 0 + } else { + if self.words[start_word_index] & !(start_mask - 1) != 0 { + return true; + } + + let remaining = start_word_index + 1..end_word_index; + if remaining.start <= remaining.end { + self.words[remaining].iter().any(|&w| w != 0) + || self.words[end_word_index] & (end_mask | (end_mask - 1)) != 0 + } else { + false + } + } + } + /// Returns `true` if the set has changed. #[inline] pub fn remove(&mut self, elem: T) -> bool { diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 323a66ddc6f..9ce4cf4293f 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -692,6 +692,25 @@ fn dense_last_set_before() { } } +#[test] +fn dense_contains_any() { + let mut set: DenseBitSet<usize> = DenseBitSet::new_empty(300); + assert!(!set.contains_any(0..300)); + set.insert_range(10..20); + set.insert_range(60..70); + set.insert_range(150..=250); + + assert!(set.contains_any(0..30)); + assert!(set.contains_any(5..100)); + assert!(set.contains_any(250..255)); + + assert!(!set.contains_any(20..59)); + assert!(!set.contains_any(256..290)); + + set.insert(22); + assert!(set.contains_any(20..59)); +} + #[bench] fn bench_insert(b: &mut Bencher) { let mut bs = DenseBitSet::new_filled(99999usize); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5bc7559d29a..f4045eeea4d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -60,10 +60,6 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate { guar.raise_fatal(); }); - if sess.opts.unstable_opts.input_stats { - input_stats::print_ast_stats(&krate, "PRE EXPANSION AST STATS", "ast-stats-1"); - } - rustc_builtin_macros::cmdline_attrs::inject( &mut krate, &sess.psess, @@ -298,7 +294,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { - input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats-2"); + input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats"); } // Needs to go *after* expansion to be able to check the results of macro expansion. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 17485a838f3..e7e60e8701a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -374,8 +374,6 @@ lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe .label = not FFI-safe .note = the type is defined here -lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI - lint_improper_ctypes_array_help = consider passing a pointer to the array lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 77dc6335113..fec23354c91 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,9 +1,7 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{ - BackendRepr, Integer, IntegerType, TagEncoding, VariantIdx, Variants, WrappingRange, -}; +use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::intravisit::VisitorExt; @@ -1284,14 +1282,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { }; } - if let Some(IntegerType::Fixed(Integer::I128, _)) = def.repr().int { - return FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_128bit, - help: None, - }; - } - use improper_ctypes::check_non_exhaustive_variant; let non_exhaustive = def.variant_list_has_applicable_non_exhaustive(); @@ -1324,10 +1314,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // but only the base type is relevant for being representable in FFI. ty::Pat(base, ..) => self.check_type_for_ffi(acc, base), - ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { - FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } - } - // Primitive types with a stable representation. ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 542653efd30..d900e16b005 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1148,8 +1148,8 @@ rustc_queries! { desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) } } - query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { - desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } + query check_type_wf(key: ()) -> Result<(), ErrorGuaranteed> { + desc { "checking that types are well-formed" } return_result_from_ensure_ok } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index f3da2a5cc8e..4da4dc3c02e 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -41,7 +41,8 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( expr: &'thir Expr<'tcx>, ) { use ExprKind::*; - match expr.kind { + let Expr { kind, ty: _, temp_lifetime: _, span: _ } = expr; + match *kind { Scope { value, region_scope: _, lint_level: _ } => { visitor.visit_expr(&visitor.thir()[value]) } @@ -191,7 +192,8 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, stmt: &'thir Stmt<'tcx>, ) { - match &stmt.kind { + let Stmt { kind } = stmt; + match kind { StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), StmtKind::Let { initializer, @@ -217,11 +219,13 @@ pub fn walk_block<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, block: &'thir Block, ) { - for &stmt in &*block.stmts { + let Block { stmts, expr, targeted_by_break: _, region_scope: _, span: _, safety_mode: _ } = + block; + for &stmt in &*stmts { visitor.visit_stmt(&visitor.thir()[stmt]); } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); + if let Some(expr) = expr { + visitor.visit_expr(&visitor.thir()[*expr]); } } @@ -229,11 +233,12 @@ pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor: &mut V, arm: &'thir Arm<'tcx>, ) { - if let Some(expr) = arm.guard { - visitor.visit_expr(&visitor.thir()[expr]) + let Arm { guard, pattern, body, lint_level: _, span: _, scope: _ } = arm; + if let Some(expr) = guard { + visitor.visit_expr(&visitor.thir()[*expr]) } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); + visitor.visit_pat(pattern); + visitor.visit_expr(&visitor.thir()[*body]); } pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( @@ -249,7 +254,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( pat: &'a Pat<'tcx>, mut callback: impl FnMut(&'a Pat<'tcx>), ) { - match &pat.kind { + let Pat { kind, ty: _, span: _ } = pat; + match kind { PatKind::Missing | PatKind::Wild | PatKind::Binding { subpattern: None, .. } diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 6b266da5a69..625e53f9959 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -382,12 +382,34 @@ pub(super) fn expand_async_drops<'tcx>( dropline_call_bb = Some(drop_call_bb); } - // value needed only for return-yields or gen-coroutines, so just const here - let value = Operand::Constant(Box::new(ConstOperand { - span: body.span, - user_ty: None, - const_: Const::from_bool(tcx, false), - })); + let value = + if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) + { + // For AsyncGen we need `yield Poll<OptRet>::Pending` + let full_yield_ty = body.yield_ty().unwrap(); + let ty::Adt(_poll_adt, args) = *full_yield_ty.kind() else { bug!() }; + let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { bug!() }; + let yield_ty = args.type_at(0); + Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + const_: Const::Unevaluated( + UnevaluatedConst::new( + tcx.require_lang_item(LangItem::AsyncGenPending, None), + tcx.mk_args(&[yield_ty.into()]), + ), + full_yield_ty, + ), + user_ty: None, + })) + } else { + // value needed only for return-yields or gen-coroutines, so just const here + Operand::Constant(Box::new(ConstOperand { + span: body.span, + user_ty: None, + const_: Const::from_bool(tcx, false), + })) + }; + use rustc_middle::mir::AssertKind::ResumedAfterDrop; let panic_bb = insert_panic_block(tcx, body, ResumedAfterDrop(coroutine_kind)); diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index cfeaee07776..5478e54a606 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -1,6 +1,6 @@ //! This module ensures that if a function's ABI requires a particular target feature, //! that target feature is enabled both on the callee and all callers. -use rustc_abi::{BackendRepr, RegKind}; +use rustc_abi::{BackendRepr, CanonAbi, RegKind, X86Call}; use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::ty::layout::LayoutCx; @@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv}; use rustc_session::lint::builtin::WASM_C_ABI; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; -use rustc_target::callconv::{ArgAbi, Conv, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::{HasWasmCAbiOpt, WasmCAbi}; use crate::errors; @@ -72,7 +72,7 @@ fn do_check_simd_vector_abi<'tcx>( } } // The `vectorcall` ABI is special in that it requires SSE2 no matter which types are being passed. - if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) { + if abi.conv == CanonAbi::X86(X86Call::Vectorcall) && !have_feature(sym::sse2) { let (span, _hir_id) = loc(); tcx.dcx().emit_err(errors::AbiRequiredTargetFeature { span, @@ -128,7 +128,7 @@ fn do_check_wasm_abi<'tcx>( if !(tcx.sess.target.arch == "wasm32" && tcx.sess.target.os == "unknown" && tcx.wasm_c_abi_opt() == WasmCAbi::Legacy { with_lint: true } - && abi.conv == Conv::C) + && abi.conv == CanonAbi::C) { return; } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1a44f4af8a6..adfea3641e6 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -834,7 +834,7 @@ impl<'a> Parser<'a> { // guides recovery in case we write `&raw expr`. if borrow_kind == ast::BorrowKind::Ref && mutbl == ast::Mutability::Not - && matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw)) + && matches!(&expr.kind, ExprKind::Path(None, p) if *p == kw::Raw) { self.expected_token_types.insert(TokenType::KwMut); self.expected_token_types.insert(TokenType::KwConst); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ccc3410674b..c37cb0881c3 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -713,7 +713,7 @@ impl<'a> Parser<'a> { /// Parses the rest of a block expression or function body. /// Precondition: already parsed the '{'. - pub(crate) fn parse_block_tail( + pub fn parse_block_tail( &mut self, lo: Span, s: BlockCheckMode, diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs index 562e288afaa..82e18ad497b 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -4,10 +4,11 @@ //! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, //! see design document in the tracking issue #89653. +use rustc_abi::CanonAbi; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; -use rustc_target::callconv::{Conv, FnAbi, PassMode}; +use rustc_target::callconv::{FnAbi, PassMode}; use tracing::instrument; mod encode; @@ -45,7 +46,7 @@ pub fn typeid_for_fnabi<'tcx>( let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); match fn_abi.conv { - Conv::C => { + CanonAbi::C => { encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); } _ => { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 7ccc785a400..06dfaf079a3 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -2,8 +2,9 @@ #![allow(rustc::usage_of_qualified_ty)] +use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; use rustc_middle::ty; -use rustc_target::callconv::{self, Conv}; +use rustc_target::callconv; use stable_mir::abi::{ AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, @@ -69,7 +70,7 @@ impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { assert!(self.args.len() >= self.fixed_count as usize); - assert!(!self.c_variadic || matches!(self.conv, Conv::C)); + assert!(!self.c_variadic || matches!(self.conv, CanonAbi::C)); FnAbi { args: self.args.as_ref().stable(tables), ret: self.ret.stable(tables), @@ -92,31 +93,37 @@ impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> { } } -impl<'tcx> Stable<'tcx> for callconv::Conv { +impl<'tcx> Stable<'tcx> for CanonAbi { type T = CallConvention; fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { match self { - Conv::C => CallConvention::C, - Conv::Rust => CallConvention::Rust, - Conv::Cold => CallConvention::Cold, - Conv::PreserveMost => CallConvention::PreserveMost, - Conv::PreserveAll => CallConvention::PreserveAll, - Conv::ArmAapcs => CallConvention::ArmAapcs, - Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, - Conv::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, - Conv::Msp430Intr => CallConvention::Msp430Intr, - Conv::X86Fastcall => CallConvention::X86Fastcall, - Conv::X86Intr => CallConvention::X86Intr, - Conv::X86Stdcall => CallConvention::X86Stdcall, - Conv::X86ThisCall => CallConvention::X86ThisCall, - Conv::X86VectorCall => CallConvention::X86VectorCall, - Conv::X86_64SysV => CallConvention::X86_64SysV, - Conv::X86_64Win64 => CallConvention::X86_64Win64, - Conv::GpuKernel => CallConvention::GpuKernel, - Conv::AvrInterrupt => CallConvention::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt, - Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt, + CanonAbi::C => CallConvention::C, + CanonAbi::Rust => CallConvention::Rust, + CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Arm(arm_call) => match arm_call { + ArmCall::Aapcs => CallConvention::ArmAapcs, + ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + ArmCall::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, + }, + CanonAbi::GpuKernel => CallConvention::GpuKernel, + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { + InterruptKind::Avr => CallConvention::AvrInterrupt, + InterruptKind::AvrNonBlocking => CallConvention::AvrNonBlockingInterrupt, + InterruptKind::Msp430 => CallConvention::Msp430Intr, + InterruptKind::RiscvMachine | InterruptKind::RiscvSupervisor => { + CallConvention::RiscvInterrupt + } + InterruptKind::X86 => CallConvention::X86Intr, + }, + CanonAbi::X86(x86_call) => match x86_call { + X86Call::Fastcall => CallConvention::X86Fastcall, + X86Call::Stdcall => CallConvention::X86Stdcall, + X86Call::SysV64 => CallConvention::X86_64SysV, + X86Call::Thiscall => CallConvention::X86ThisCall, + X86Call::Vectorcall => CallConvention::X86VectorCall, + X86Call::Win64 => CallConvention::X86_64Win64, + }, } } } diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 0a5dcc66347..70830fa07b6 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -1,6 +1,6 @@ -use rustc_abi::{HasDataLayout, TyAbiInterface}; +use rustc_abi::{ArmCall, CanonAbi, HasDataLayout, TyAbiInterface}; -use crate::callconv::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform}; +use crate::callconv::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::spec::HasTargetSpec; fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform> @@ -90,7 +90,7 @@ where // If this is a target with a hard-float ABI, and the function is not explicitly // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates. let vfp = cx.target_spec().llvm_target.ends_with("hf") - && fn_abi.conv != Conv::ArmAapcs + && fn_abi.conv != CanonAbi::Arm(ArmCall::Aapcs) && !fn_abi.c_variadic; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 907614520a2..d2e49cea647 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -1,13 +1,12 @@ -use std::fmt::Display; -use std::str::FromStr; use std::{fmt, iter}; use rustc_abi::{ - AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, Scalar, - Size, TyAbiInterface, TyAndLayout, + AddressSpace, Align, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Primitive, Reg, RegKind, + Scalar, Size, TyAbiInterface, TyAndLayout, }; use rustc_macros::HashStable_Generic; +pub use crate::spec::AbiMap; use crate::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, RustcAbi, WasmCAbi}; mod aarch64; @@ -530,41 +529,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum Conv { - // General language calling conventions, for which every target - // should have its own backend (e.g. LLVM) support. - C, - Rust, - - Cold, - PreserveMost, - PreserveAll, - - // Target-specific calling conventions. - ArmAapcs, - CCmseNonSecureCall, - CCmseNonSecureEntry, - - Msp430Intr, - - GpuKernel, - - X86Fastcall, - X86Intr, - X86Stdcall, - X86ThisCall, - X86VectorCall, - - X86_64SysV, - X86_64Win64, - - AvrInterrupt, - AvrNonBlockingInterrupt, - - RiscvInterrupt { kind: RiscvInterruptKind }, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum RiscvInterruptKind { Machine, Supervisor, @@ -605,7 +569,7 @@ pub struct FnAbi<'a, Ty> { /// This can be used to know whether an argument is variadic or not. pub fixed_count: u32, /// The calling convention of this function. - pub conv: Conv, + pub conv: CanonAbi, /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, } @@ -696,7 +660,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), "nvptx64" => { - let abi = cx.target_spec().adjust_abi(abi, self.c_variadic); if abi == ExternAbi::PtxKernel || abi == ExternAbi::GpuKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) } else { @@ -863,70 +826,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } -impl FromStr for Conv { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "C" => Ok(Conv::C), - "Rust" => Ok(Conv::Rust), - "RustCold" => Ok(Conv::Rust), - "ArmAapcs" => Ok(Conv::ArmAapcs), - "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), - "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry), - "Msp430Intr" => Ok(Conv::Msp430Intr), - "X86Fastcall" => Ok(Conv::X86Fastcall), - "X86Intr" => Ok(Conv::X86Intr), - "X86Stdcall" => Ok(Conv::X86Stdcall), - "X86ThisCall" => Ok(Conv::X86ThisCall), - "X86VectorCall" => Ok(Conv::X86VectorCall), - "X86_64SysV" => Ok(Conv::X86_64SysV), - "X86_64Win64" => Ok(Conv::X86_64Win64), - "GpuKernel" => Ok(Conv::GpuKernel), - "AvrInterrupt" => Ok(Conv::AvrInterrupt), - "AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt), - "RiscvInterrupt(machine)" => { - Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }) - } - "RiscvInterrupt(supervisor)" => { - Ok(Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }) - } - _ => Err(format!("'{s}' is not a valid value for entry function call convention.")), - } - } -} - -fn conv_to_externabi(conv: &Conv) -> ExternAbi { - match conv { - Conv::C => ExternAbi::C { unwind: false }, - Conv::Rust => ExternAbi::Rust, - Conv::PreserveMost => ExternAbi::RustCold, - Conv::ArmAapcs => ExternAbi::Aapcs { unwind: false }, - Conv::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, - Conv::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, - Conv::Msp430Intr => ExternAbi::Msp430Interrupt, - Conv::GpuKernel => ExternAbi::GpuKernel, - Conv::X86Fastcall => ExternAbi::Fastcall { unwind: false }, - Conv::X86Intr => ExternAbi::X86Interrupt, - Conv::X86Stdcall => ExternAbi::Stdcall { unwind: false }, - Conv::X86ThisCall => ExternAbi::Thiscall { unwind: false }, - Conv::X86VectorCall => ExternAbi::Vectorcall { unwind: false }, - Conv::X86_64SysV => ExternAbi::SysV64 { unwind: false }, - Conv::X86_64Win64 => ExternAbi::Win64 { unwind: false }, - Conv::AvrInterrupt => ExternAbi::AvrInterrupt, - Conv::AvrNonBlockingInterrupt => ExternAbi::AvrNonBlockingInterrupt, - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine } => ExternAbi::RiscvInterruptM, - Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor } => ExternAbi::RiscvInterruptS, - Conv::Cold | Conv::PreserveAll => unreachable!(), - } -} - -impl Display for Conv { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", conv_to_externabi(self)) - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 8d6f8f4c6f6..4fcc477921b 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -92,38 +92,6 @@ impl<A: ToJson> ToJson for Option<A> { } } -impl ToJson for crate::callconv::Conv { - fn to_json(&self) -> Json { - let buf: String; - let s = match self { - Self::C => "C", - Self::Rust => "Rust", - Self::Cold => "Cold", - Self::PreserveMost => "PreserveMost", - Self::PreserveAll => "PreserveAll", - Self::ArmAapcs => "ArmAapcs", - Self::CCmseNonSecureCall => "CCmseNonSecureCall", - Self::CCmseNonSecureEntry => "CCmseNonSecureEntry", - Self::Msp430Intr => "Msp430Intr", - Self::X86Fastcall => "X86Fastcall", - Self::X86Intr => "X86Intr", - Self::X86Stdcall => "X86Stdcall", - Self::X86ThisCall => "X86ThisCall", - Self::X86VectorCall => "X86VectorCall", - Self::X86_64SysV => "X86_64SysV", - Self::X86_64Win64 => "X86_64Win64", - Self::GpuKernel => "GpuKernel", - Self::AvrInterrupt => "AvrInterrupt", - Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt", - Self::RiscvInterrupt { kind } => { - buf = format!("RiscvInterrupt({})", kind.as_str()); - &buf - } - }; - Json::String(s.to_owned()) - } -} - impl ToJson for TargetMetadata { fn to_json(&self) -> Json { json!({ @@ -140,3 +108,9 @@ impl ToJson for rustc_abi::Endian { self.as_str().to_json() } } + +impl ToJson for rustc_abi::CanonAbi { + fn to_json(&self) -> Json { + self.to_string().to_json() + } +} diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs new file mode 100644 index 00000000000..d9101f79f04 --- /dev/null +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -0,0 +1,187 @@ +use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call}; + +use crate::spec::Target; + +/// Mapping for ExternAbi to CanonAbi according to a Target +/// +/// A maybe-transitional structure circa 2025 for hosting future experiments in +/// encapsulating arch-specific ABI lowering details to make them more testable. +#[derive(Clone, Debug)] +pub struct AbiMap { + arch: Arch, + os: OsKind, +} + +#[derive(Copy, Clone, Debug)] +pub enum AbiMapping { + /// this ABI is exactly mapped for this platform + Direct(CanonAbi), + /// we don't yet warn on this, but we will + Deprecated(CanonAbi), + Invalid, +} + +impl AbiMapping { + pub fn into_option(self) -> Option<CanonAbi> { + match self { + Self::Direct(abi) | Self::Deprecated(abi) => Some(abi), + Self::Invalid => None, + } + } + + pub fn unwrap(self) -> CanonAbi { + self.into_option().unwrap() + } + + pub fn is_mapped(self) -> bool { + self.into_option().is_some() + } +} + +impl AbiMap { + pub fn from_target(target: &Target) -> Self { + // the purpose of this little exercise is to force listing what affects these mappings + let arch = match &*target.arch { + "aarch64" => Arch::Aarch64, + "amdgpu" => Arch::Amdgpu, + "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M), + "arm" => Arch::Arm(ArmVer::Other), + "avr" => Arch::Avr, + "msp430" => Arch::Msp430, + "nvptx64" => Arch::Nvptx, + "riscv32" | "riscv64" => Arch::Riscv, + "x86" => Arch::X86, + "x86_64" => Arch::X86_64, + _ => Arch::Other, + }; + let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other }; + AbiMap { arch, os } + } + + pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping { + let AbiMap { os, arch } = *self; + + let canon_abi = match (extern_abi, arch) { + // infallible lowerings + (ExternAbi::C { .. }, _) => CanonAbi::C, + (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust, + (ExternAbi::Unadjusted, _) => CanonAbi::C, + + (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, + (ExternAbi::RustCold, _) => CanonAbi::RustCold, + + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { + CanonAbi::X86(X86Call::Stdcall) + } + (ExternAbi::System { .. }, _) => CanonAbi::C, + + // fallible lowerings + (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), + (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), + (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C, + (ExternAbi::EfiApi, _) => return AbiMapping::Invalid, + + (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), + (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { + CanonAbi::Arm(ArmCall::CCmseNonSecureCall) + } + (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { + CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) + } + (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => { + return AbiMapping::Invalid; + } + + (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C, + (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C), + + (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall), + (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall), + (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall), + (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => { + CanonAbi::X86(X86Call::Vectorcall) + } + (ExternAbi::Vectorcall { .. }, _) if os == OsKind::Windows => { + return AbiMapping::Deprecated(CanonAbi::C); + } + (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64), + (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), + (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid, + + (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, + (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, + + (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr), + (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => { + CanonAbi::Interrupt(InterruptKind::AvrNonBlocking) + } + (ExternAbi::Msp430Interrupt, Arch::Msp430) => { + CanonAbi::Interrupt(InterruptKind::Msp430) + } + (ExternAbi::RiscvInterruptM, Arch::Riscv) => { + CanonAbi::Interrupt(InterruptKind::RiscvMachine) + } + (ExternAbi::RiscvInterruptS, Arch::Riscv) => { + CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) + } + (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => { + CanonAbi::Interrupt(InterruptKind::X86) + } + ( + ExternAbi::AvrInterrupt + | ExternAbi::AvrNonBlockingInterrupt + | ExternAbi::Msp430Interrupt + | ExternAbi::RiscvInterruptM + | ExternAbi::RiscvInterruptS + | ExternAbi::X86Interrupt, + _, + ) => return AbiMapping::Invalid, + }; + + AbiMapping::Direct(canon_abi) + } +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum Arch { + Aarch64, + Amdgpu, + Arm(ArmVer), + Avr, + Msp430, + Nvptx, + Riscv, + X86, + X86_64, + /// Architectures which don't need other considerations for ABI lowering + Other, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum OsKind { + Windows, + Other, +} + +#[derive(Debug, PartialEq, Copy, Clone)] +enum ArmVer { + ThumbV8M, + Other, +} diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index be71da76b4a..54b06d9f9b4 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -2,10 +2,12 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::str::FromStr; +use rustc_abi::ExternAbi; use serde_json::Value; use super::{Target, TargetKind, TargetOptions, TargetWarnings}; use crate::json::{Json, ToJson}; +use crate::spec::AbiMap; impl Target { /// Loads a target descriptor from a JSON object. @@ -515,18 +517,6 @@ impl Target { } } } ); - ($key_name:ident, Conv) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match super::Conv::from_str(s) { - Ok(c) => { - base.$key_name = c; - Some(Ok(())) - } - Err(e) => Some(Err(e)) - } - })).unwrap_or(Ok(())) - } ); } if let Some(j) = obj.remove("target-endian") { @@ -660,9 +650,23 @@ impl Target { key!(supports_stack_protector, bool); key!(small_data_threshold_support, SmallDataThresholdSupport)?; key!(entry_name); - key!(entry_abi, Conv)?; key!(supports_xray, bool); + // we're going to run `update_from_cli`, but that won't change the target's AbiMap + // FIXME: better factor the Target definition so we enforce this on a type level + let abi_map = AbiMap::from_target(&base); + + if let Some(abi_str) = obj.remove("entry-abi") { + if let Json::String(abi_str) = abi_str { + match abi_str.parse::<ExternAbi>() { + Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(), + Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")), + } + } else { + incorrect_type.push("entry-abi".to_owned()) + } + } + base.update_from_cli(); base.check_consistency(TargetKind::Json)?; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 303be54a6d7..6529c2d72c8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -43,7 +43,7 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{ - Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors, + Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors, }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_fs_util::try_canonicalize; @@ -53,15 +53,16 @@ use rustc_span::{Symbol, kw, sym}; use serde_json::Value; use tracing::debug; -use crate::callconv::Conv; use crate::json::{Json, ToJson}; use crate::spec::crt_objects::CrtObjects; pub mod crt_objects; +mod abi_map; mod base; mod json; +pub use abi_map::AbiMap; pub use base::apple; pub use base::avr::ef_avr_arch; @@ -2655,9 +2656,9 @@ pub struct TargetOptions { /// Default value is "main" pub entry_name: StaticCow<str>, - /// The ABI of entry function. - /// Default value is `Conv::C`, i.e. C call convention - pub entry_abi: Conv, + /// The ABI of the entry function. + /// Default value is `CanonAbi::C` + pub entry_abi: CanonAbi, /// Whether the target supports XRay instrumentation. pub supports_xray: bool, @@ -2888,7 +2889,7 @@ impl Default for TargetOptions { generate_arange_section: true, supports_stack_protector: true, entry_name: "main".into(), - entry_abi: Conv::C, + entry_abi: CanonAbi::C, supports_xray: false, small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, } @@ -2914,114 +2915,9 @@ impl DerefMut for Target { } impl Target { - /// Given a function ABI, turn it into the correct ABI for this target. - pub fn adjust_abi(&self, abi: ExternAbi, c_variadic: bool) -> ExternAbi { - use ExternAbi::*; - match abi { - // On Windows, `extern "system"` behaves like msvc's `__stdcall`. - // `__stdcall` only applies on x86 and on non-variadic functions: - // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 - System { unwind } => { - if self.is_like_windows && self.arch == "x86" && !c_variadic { - Stdcall { unwind } - } else { - C { unwind } - } - } - - EfiApi => { - if self.arch == "arm" { - Aapcs { unwind: false } - } else if self.arch == "x86_64" { - Win64 { unwind: false } - } else { - C { unwind: false } - } - } - - // See commentary in `is_abi_supported`. - Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => { - if self.arch == "x86" { abi } else { C { unwind } } - } - Vectorcall { unwind } => { - if ["x86", "x86_64"].contains(&&*self.arch) { - abi - } else { - C { unwind } - } - } - - // The Windows x64 calling convention we use for `extern "Rust"` - // <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation> - // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost` - // (that we use by default for `extern "rust-cold"`) doesn't save any of those. - // So to avoid bloating callers, just use the Rust convention here. - RustCold if self.is_like_windows && self.arch == "x86_64" => Rust, - - abi => abi, - } - } - pub fn is_abi_supported(&self, abi: ExternAbi) -> bool { - use ExternAbi::*; - match abi { - Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => { - true - } - EfiApi => { - ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..]) - } - X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), - Aapcs { .. } => "arm" == self.arch, - CCmseNonSecureCall | CCmseNonSecureEntry => { - ["thumbv8m.main-none-eabi", "thumbv8m.main-none-eabihf", "thumbv8m.base-none-eabi"] - .contains(&&self.llvm_target[..]) - } - Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", - PtxKernel => self.arch == "nvptx64", - GpuKernel => ["amdgpu", "nvptx64"].contains(&&self.arch[..]), - Msp430Interrupt => self.arch == "msp430", - RiscvInterruptM | RiscvInterruptS => ["riscv32", "riscv64"].contains(&&self.arch[..]), - AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", - Thiscall { .. } => self.arch == "x86", - // On windows these fall-back to platform native calling convention (C) when the - // architecture is not supported. - // - // This is I believe a historical accident that has occurred as part of Microsoft - // striving to allow most of the code to "just" compile when support for 64-bit x86 - // was added and then later again, when support for ARM architectures was added. - // - // This is well documented across MSDN. Support for this in Rust has been added in - // #54576. This makes much more sense in context of Microsoft's C++ than it does in - // Rust, but there isn't much leeway remaining here to change it back at the time this - // comment has been written. - // - // Following are the relevant excerpts from the MSDN documentation. - // - // > The __vectorcall calling convention is only supported in native code on x86 and - // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above. - // > ... - // > On ARM machines, __vectorcall is accepted and ignored by the compiler. - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160 - // - // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160 - // - // > In most cases, keywords or compiler switches that specify an unsupported - // > convention on a particular platform are ignored, and the platform default - // > convention is used. - // - // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions - Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true, - // Outside of Windows we want to only support these calling conventions for the - // architectures for which these calling conventions are actually well defined. - Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, - Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true, - // Reject these calling conventions everywhere else. - Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false, - } + let abi_map = AbiMap::from_target(self); + abi_map.canonize_abi(abi, false).is_mapped() } /// Minimum integer size in bits that this target can perform atomic diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index 07f853dacaf..0cf6a879462 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -5,7 +5,8 @@ // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features. -use crate::callconv::Conv; +use rustc_abi::{CanonAbi, X86Call}; + use crate::spec::{RustcAbi, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { @@ -13,7 +14,7 @@ pub(crate) fn target() -> Target { base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); - base.entry_abi = Conv::X86_64Win64; + base.entry_abi = CanonAbi::X86(X86Call::Win64); // We disable MMX and SSE for now, even though UEFI allows using them. Problem is, you have to // enable these CPU features explicitly before their first use, otherwise their instructions diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 576c9bd6b57..682c4c5068f 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -710,29 +710,35 @@ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-end ]; +#[rustfmt::skip] const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), ("high-word", Unstable(sym::s390x_target_feature), &[]), + // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. + ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), + ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), + ("miscellaneous-extensions-2", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]), ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]), ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), ("vector", Unstable(sym::s390x_target_feature), &[]), ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]), ("vector-enhancements-2", Unstable(sym::s390x_target_feature), &["vector-enhancements-1"]), + ("vector-enhancements-3", Unstable(sym::s390x_target_feature), &["vector-enhancements-2"]), ("vector-packed-decimal", Unstable(sym::s390x_target_feature), &["vector"]), - ( - "vector-packed-decimal-enhancement", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal"], - ), - ( - "vector-packed-decimal-enhancement-2", - Unstable(sym::s390x_target_feature), - &["vector-packed-decimal-enhancement"], - ), + ("vector-packed-decimal-enhancement", Unstable(sym::s390x_target_feature), &["vector-packed-decimal"]), + ("vector-packed-decimal-enhancement-2", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement"]), + ("vector-packed-decimal-enhancement-3", Unstable(sym::s390x_target_feature), &["vector-packed-decimal-enhancement-2"]), // tidy-alphabetical-end ]; diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 9b949a0a795..8232da4df43 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -72,8 +72,6 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds -trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment - trait_selection_await_both_futures = consider `await`ing on both `Future`s trait_selection_await_future = consider `await`ing on the `Future` trait_selection_await_note = calling an async function returns a future @@ -123,6 +121,8 @@ trait_selection_closure_kind_requirement = the requirement to implement `{$trait trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait trait_selection_consider_specifying_length = consider specifying the actual array length +trait_selection_coro_closure_not_fn = {$coro_kind}closure does not implement `{$kind}` because it captures state from its environment + trait_selection_data_flows = ...but data{$label_var1_exists -> [true] {" "}from `{$label_var1}` *[false] {""} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 9b5e421e0e4..fc5be111144 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -42,9 +42,7 @@ use super::{ use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; use crate::error_reporting::traits::report_dyn_incompatibility; -use crate::errors::{ - AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, -}; +use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn}; use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ @@ -886,9 +884,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // is unimplemented is because async closures don't implement `Fn`/`FnMut` // if they have captures. if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce { - let mut err = self.dcx().create_err(AsyncClosureNotFn { + let coro_kind = match self + .tcx + .coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id)) + .unwrap() + { + rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(), + coro => coro.to_string(), + }; + let mut err = self.dcx().create_err(CoroClosureNotFn { span: self.tcx.def_span(closure_def_id), kind: expected_kind.as_str(), + coro_kind, }); self.note_obligation_cause(&mut err, &obligation); return Some(err.emit()); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 779c861637a..0bea308ed5c 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -201,11 +201,12 @@ pub struct ClosureFnMutLabel { } #[derive(Diagnostic)] -#[diag(trait_selection_async_closure_not_fn)] -pub(crate) struct AsyncClosureNotFn { +#[diag(trait_selection_coro_closure_not_fn)] +pub(crate) struct CoroClosureNotFn { #[primary_span] pub span: Span, pub kind: &'static str, + pub coro_kind: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 7d869b27445..97ecf9702e6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -11,7 +11,7 @@ use std::ops::ControlFlow; use hir::LangItem; use hir::def_id::DefId; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_hir as hir; +use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind}; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate}; @@ -438,6 +438,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self, candidates))] fn assemble_async_closure_candidates( &mut self, obligation: &PolyTraitObligation<'tcx>, @@ -446,15 +447,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let goal_kind = self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); + debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind()); match *obligation.self_ty().skip_binder().kind() { - ty::CoroutineClosure(_, args) => { + ty::CoroutineClosure(def_id, args) => { if let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() && !closure_kind.extends(goal_kind) { return; } - candidates.vec.push(AsyncClosureCandidate); + + // Make sure this is actually an async closure. + let Some(coroutine_kind) = + self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id)) + else { + bug!("coroutine with no kind"); + }; + + debug!(?coroutine_kind); + match coroutine_kind { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + candidates.vec.push(AsyncClosureCandidate); + } + _ => (), + } } // Closures and fn pointers implement `AsyncFn*` if their return types // implement `Future`, which is checked later. diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2b49d7ac8b5..83d7416b03e 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::callconv::{ - ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, RiscvInterruptKind, + AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode, }; use tracing::debug; @@ -240,45 +240,6 @@ fn fn_sig_for_fn_abi<'tcx>( } } -#[inline] -fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv { - use rustc_abi::ExternAbi::*; - match tcx.sess.target.adjust_abi(abi, c_variadic) { - Rust | RustCall => Conv::Rust, - - // This is intentionally not using `Conv::Cold`, as that has to preserve - // even SIMD registers, which is generally not a good trade-off. - RustCold => Conv::PreserveMost, - - // It's the ABI's job to select this, not ours. - System { .. } => bug!("system abi should be selected elsewhere"), - EfiApi => bug!("eficall abi should be selected elsewhere"), - - Stdcall { .. } => Conv::X86Stdcall, - Fastcall { .. } => Conv::X86Fastcall, - Vectorcall { .. } => Conv::X86VectorCall, - Thiscall { .. } => Conv::X86ThisCall, - C { .. } => Conv::C, - Unadjusted => Conv::C, - Win64 { .. } => Conv::X86_64Win64, - SysV64 { .. } => Conv::X86_64SysV, - Aapcs { .. } => Conv::ArmAapcs, - CCmseNonSecureCall => Conv::CCmseNonSecureCall, - CCmseNonSecureEntry => Conv::CCmseNonSecureEntry, - PtxKernel => Conv::GpuKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - GpuKernel => Conv::GpuKernel, - AvrInterrupt => Conv::AvrInterrupt, - AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, - RiscvInterruptM => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Machine }, - RiscvInterruptS => Conv::RiscvInterrupt { kind: RiscvInterruptKind::Supervisor }, - - // These API constants ought to be more specific... - Cdecl { .. } => Conv::C, - } -} - fn fn_abi_of_fn_ptr<'tcx>( tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>, @@ -529,7 +490,8 @@ fn fn_abi_new_uncached<'tcx>( }; let sig = tcx.normalize_erasing_regions(cx.typing_env, sig); - let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic); + let abi_map = AbiMap::from_target(&tcx.sess.target); + let conv = abi_map.canonize_abi(sig.abi, sig.c_variadic).unwrap(); let mut inputs = sig.inputs(); let extra_args = if sig.abi == ExternAbi::RustCall { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a9917192144..05ca6f10323 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -4,7 +4,6 @@ use std::ops::Deref; use rustc_ast_ir::Movability; use rustc_index::bit_set::DenseBitSet; -use smallvec::SmallVec; use crate::fold::TypeFoldable; use crate::inherent::*; @@ -382,28 +381,45 @@ impl<T, R> CollectAndApply<T, R> for T { F: FnOnce(&[T]) -> R, { // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`. - match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap(); - let t1 = iter.next().unwrap(); - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::<SmallVec<[_; 8]>>()), - } + // common length lists, to avoid the overhead of `Vec` creation. + + let Some(t0) = iter.next() else { + return f(&[]); + }; + + let Some(t1) = iter.next() else { + return f(&[t0]); + }; + + let Some(t2) = iter.next() else { + return f(&[t0, t1]); + }; + + let Some(t3) = iter.next() else { + return f(&[t0, t1, t2]); + }; + + let Some(t4) = iter.next() else { + return f(&[t0, t1, t2, t3]); + }; + + let Some(t5) = iter.next() else { + return f(&[t0, t1, t2, t3, t4]); + }; + + let Some(t6) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5]); + }; + + let Some(t7) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5, t6]); + }; + + let Some(t8) = iter.next() else { + return f(&[t0, t1, t2, t3, t4, t5, t6, t7]); + }; + + f(&[t0, t1, t2, t3, t4, t5, t6, t7, t8].into_iter().chain(iter).collect::<Vec<_>>()) } } @@ -419,29 +435,57 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> { F: FnOnce(&[T]) -> R, { // This code is hot enough that it's worth specializing for the most - // common length lists, to avoid the overhead of `SmallVec` creation. - // Lengths 0, 1, and 2 typically account for ~95% of cases. If - // `size_hint` is incorrect a panic will occur via an `unwrap` or an - // `assert`, unless a failure happens first, in which case the result - // will be an error anyway. - Ok(match iter.size_hint() { - (0, Some(0)) => { - assert!(iter.next().is_none()); - f(&[]) - } - (1, Some(1)) => { - let t0 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0]) - } - (2, Some(2)) => { - let t0 = iter.next().unwrap()?; - let t1 = iter.next().unwrap()?; - assert!(iter.next().is_none()); - f(&[t0, t1]) - } - _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?), - }) + // common length lists, to avoid the overhead of `Vec` creation. + + let Some(t0) = iter.next() else { + return Ok(f(&[])); + }; + let t0 = t0?; + + let Some(t1) = iter.next() else { + return Ok(f(&[t0])); + }; + let t1 = t1?; + + let Some(t2) = iter.next() else { + return Ok(f(&[t0, t1])); + }; + let t2 = t2?; + + let Some(t3) = iter.next() else { + return Ok(f(&[t0, t1, t2])); + }; + let t3 = t3?; + + let Some(t4) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3])); + }; + let t4 = t4?; + + let Some(t5) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4])); + }; + let t5 = t5?; + + let Some(t6) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5])); + }; + let t6 = t6?; + + let Some(t7) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5, t6])); + }; + let t7 = t7?; + + let Some(t8) = iter.next() else { + return Ok(f(&[t0, t1, t2, t3, t4, t5, t6, t7])); + }; + let t8 = t8?; + + Ok(f(&[Ok(t0), Ok(t1), Ok(t2), Ok(t3), Ok(t4), Ok(t5), Ok(t6), Ok(t7), Ok(t8)] + .into_iter() + .chain(iter) + .collect::<Result<Vec<_>, _>>()?)) } } |
