Skip to content

Commit fb5bcc1

Browse files
authored
Merge branch 'rust-lang:master' into master
2 parents db8d5ec + 425e142 commit fb5bcc1

File tree

1,243 files changed

+61564
-7435
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,243 files changed

+61564
-7435
lines changed

compiler/rustc_abi/src/canon_abi.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use std::fmt;
2+
3+
#[cfg(feature = "nightly")]
4+
use rustc_macros::HashStable_Generic;
5+
6+
use crate::ExternAbi;
7+
8+
/// Calling convention to determine codegen
9+
///
10+
/// CanonAbi erases certain distinctions ExternAbi preserves, but remains target-dependent.
11+
/// There are still both target-specific variants and aliasing variants, though much fewer.
12+
/// The reason for this step is the frontend may wish to show an ExternAbi but implement that ABI
13+
/// using a different ABI than the string per se, or describe irrelevant differences, e.g.
14+
/// - extern "system"
15+
/// - extern "cdecl"
16+
/// - extern "C-unwind"
17+
/// In that sense, this erases mere syntactic distinctions to create a canonical *directive*,
18+
/// rather than picking the "actual" ABI.
19+
#[derive(Copy, Clone, Debug)]
20+
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
21+
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
22+
pub enum CanonAbi {
23+
// NOTE: the use of nested variants for some ABIs is for many targets they don't matter,
24+
// and this pushes the complexity of their reasoning to target-specific code,
25+
// allowing a `match` to easily exhaustively ignore these subcategories of variants.
26+
// Otherwise it is very tempting to avoid matching exhaustively!
27+
C,
28+
Rust,
29+
RustCold,
30+
31+
/// ABIs relevant to 32-bit Arm targets
32+
Arm(ArmCall),
33+
/// ABI relevant to GPUs: the entry point for a GPU kernel
34+
GpuKernel,
35+
36+
/// ABIs relevant to bare-metal interrupt targets
37+
// FIXME(workingjubilee): a particular reason for this nesting is we might not need these?
38+
// interrupt ABIs should have the same properties:
39+
// - uncallable by Rust calls, as LLVM rejects it in most cases
40+
// - uses a preserve-all-registers *callee* convention
41+
// - should always return `-> !` (effectively... it can't use normal `ret`)
42+
// what differs between targets is
43+
// - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically
44+
// - may need special prologues/epilogues for some interrupts, without affecting "call ABI"
45+
Interrupt(InterruptKind),
46+
47+
/// ABIs relevant to Windows or x86 targets
48+
X86(X86Call),
49+
}
50+
51+
impl fmt::Display for CanonAbi {
52+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53+
self.to_erased_extern_abi().as_str().fmt(f)
54+
}
55+
}
56+
57+
impl CanonAbi {
58+
/// convert to the ExternAbi that *shares a string* with this CanonAbi
59+
///
60+
/// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls.
61+
/// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values,
62+
/// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data.
63+
const fn to_erased_extern_abi(self) -> ExternAbi {
64+
match self {
65+
CanonAbi::C => ExternAbi::C { unwind: false },
66+
CanonAbi::Rust => ExternAbi::Rust,
67+
CanonAbi::RustCold => ExternAbi::RustCold,
68+
CanonAbi::Arm(arm_call) => match arm_call {
69+
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
70+
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
71+
ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry,
72+
},
73+
CanonAbi::GpuKernel => ExternAbi::GpuKernel,
74+
CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
75+
InterruptKind::Avr => ExternAbi::AvrInterrupt,
76+
InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt,
77+
InterruptKind::Msp430 => ExternAbi::Msp430Interrupt,
78+
InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM,
79+
InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS,
80+
InterruptKind::X86 => ExternAbi::X86Interrupt,
81+
},
82+
CanonAbi::X86(x86_call) => match x86_call {
83+
X86Call::Fastcall => ExternAbi::Fastcall { unwind: false },
84+
X86Call::Stdcall => ExternAbi::Stdcall { unwind: false },
85+
X86Call::SysV64 => ExternAbi::SysV64 { unwind: false },
86+
X86Call::Thiscall => ExternAbi::Thiscall { unwind: false },
87+
X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false },
88+
X86Call::Win64 => ExternAbi::Win64 { unwind: false },
89+
},
90+
}
91+
}
92+
}
93+
94+
/// Callee codegen for interrupts
95+
///
96+
/// This is named differently from the "Call" enums because it is different:
97+
/// these "ABI" differences are not relevant to callers, since there is "no caller".
98+
/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar.
99+
#[derive(Copy, Clone, Debug)]
100+
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
101+
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
102+
pub enum InterruptKind {
103+
Avr,
104+
AvrNonBlocking,
105+
Msp430,
106+
RiscvMachine,
107+
RiscvSupervisor,
108+
X86,
109+
}
110+
111+
/// ABIs defined for x86-{32,64}
112+
///
113+
/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now?
114+
#[derive(Clone, Copy, Debug)]
115+
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
116+
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
117+
pub enum X86Call {
118+
/// "fastcall" has both GNU and Windows variants
119+
Fastcall,
120+
/// "stdcall" has both GNU and Windows variants
121+
Stdcall,
122+
SysV64,
123+
Thiscall,
124+
Vectorcall,
125+
Win64,
126+
}
127+
128+
/// ABIs defined for 32-bit Arm
129+
#[derive(Copy, Clone, Debug)]
130+
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
131+
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
132+
pub enum ArmCall {
133+
Aapcs,
134+
CCmseNonSecureCall,
135+
CCmseNonSecureEntry,
136+
}

compiler/rustc_abi/src/extern_abi.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
77
#[cfg(feature = "nightly")]
88
use rustc_macros::{Decodable, Encodable};
99

10+
use crate::AbiFromStrErr;
11+
1012
#[cfg(test)]
1113
mod tests;
1214

@@ -99,11 +101,6 @@ macro_rules! abi_impls {
99101
}
100102
}
101103

102-
#[derive(Debug)]
103-
pub enum AbiFromStrErr {
104-
Unknown,
105-
}
106-
107104
abi_impls! {
108105
ExternAbi = {
109106
C { unwind: false } =><= "C",

compiler/rustc_abi/src/layout.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
758758
niche_variants,
759759
niche_start,
760760
},
761-
tag_field: 0,
761+
tag_field: FieldIdx::new(0),
762762
variants: IndexVec::new(),
763763
},
764764
fields: FieldsShape::Arbitrary {
@@ -1072,7 +1072,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10721072
variants: Variants::Multiple {
10731073
tag,
10741074
tag_encoding: TagEncoding::Direct,
1075-
tag_field: 0,
1075+
tag_field: FieldIdx::new(0),
10761076
variants: IndexVec::new(),
10771077
},
10781078
fields: FieldsShape::Arbitrary {

compiler/rustc_abi/src/layout/coroutine.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub(super) fn layout<
158158
// Build a prefix layout, including "promoting" all ineligible
159159
// locals as part of the prefix. We compute the layout of all of
160160
// these fields at once to get optimal packing.
161-
let tag_index = prefix_layouts.len();
161+
let tag_index = prefix_layouts.next_index();
162162

163163
// `variant_fields` already accounts for the reserved variants, so no need to add them.
164164
let max_discr = (variant_fields.len() - 1) as u128;
@@ -187,7 +187,7 @@ pub(super) fn layout<
187187

188188
// "a" (`0..b_start`) and "b" (`b_start..`) correspond to
189189
// "outer" and "promoted" fields respectively.
190-
let b_start = FieldIdx::new(tag_index + 1);
190+
let b_start = tag_index.plus(1);
191191
let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index()));
192192
let offsets_a = offsets;
193193

compiler/rustc_abi/src/lib.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ use rustc_index::{Idx, IndexSlice, IndexVec};
5555
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
5656

5757
mod callconv;
58+
mod canon_abi;
59+
mod extern_abi;
5860
mod layout;
5961
#[cfg(test)]
6062
mod tests;
6163

62-
mod extern_abi;
63-
6464
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
65+
pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
6566
pub use extern_abi::{ExternAbi, all_names};
6667
#[cfg(feature = "nightly")]
6768
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
@@ -1572,7 +1573,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
15721573
Multiple {
15731574
tag: Scalar,
15741575
tag_encoding: TagEncoding<VariantIdx>,
1575-
tag_field: usize,
1576+
tag_field: FieldIdx,
15761577
variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
15771578
},
15781579
}
@@ -1895,3 +1896,11 @@ pub enum StructKind {
18951896
/// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
18961897
Prefixed(Size, Align),
18971898
}
1899+
1900+
#[derive(Clone, Debug)]
1901+
pub enum AbiFromStrErr {
1902+
/// not a known ABI
1903+
Unknown,
1904+
/// no "-unwind" variant can be used here
1905+
NoExplicitUnwind,
1906+
}

compiler/rustc_ast/src/ast.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,15 @@ pub struct Path {
9999

100100
impl PartialEq<Symbol> for Path {
101101
#[inline]
102-
fn eq(&self, symbol: &Symbol) -> bool {
103-
matches!(&self.segments[..], [segment] if segment.ident.name == *symbol)
102+
fn eq(&self, name: &Symbol) -> bool {
103+
if let [segment] = self.segments.as_ref()
104+
&& segment.args.is_none()
105+
&& segment.ident.name == *name
106+
{
107+
true
108+
} else {
109+
false
110+
}
104111
}
105112
}
106113

@@ -120,17 +127,6 @@ impl Path {
120127
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
121128
}
122129

123-
pub fn is_ident(&self, name: Symbol) -> bool {
124-
if let [segment] = self.segments.as_ref()
125-
&& segment.args.is_none()
126-
&& segment.ident.name == name
127-
{
128-
true
129-
} else {
130-
false
131-
}
132-
}
133-
134130
pub fn is_global(&self) -> bool {
135131
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
136132
}
@@ -2465,6 +2461,39 @@ impl TyKind {
24652461
None
24662462
}
24672463
}
2464+
2465+
/// Returns `true` if this type is considered a scalar primitive (e.g.,
2466+
/// `i32`, `u8`, `bool`, etc).
2467+
///
2468+
/// This check is based on **symbol equality** and does **not** remove any
2469+
/// path prefixes or references. If a type alias or shadowing is present
2470+
/// (e.g., `type i32 = CustomType;`), this method will still return `true`
2471+
/// for `i32`, even though it may not refer to the primitive type.
2472+
pub fn maybe_scalar(&self) -> bool {
2473+
let Some(ty_sym) = self.is_simple_path() else {
2474+
// unit type
2475+
return self.is_unit();
2476+
};
2477+
matches!(
2478+
ty_sym,
2479+
sym::i8
2480+
| sym::i16
2481+
| sym::i32
2482+
| sym::i64
2483+
| sym::i128
2484+
| sym::u8
2485+
| sym::u16
2486+
| sym::u32
2487+
| sym::u64
2488+
| sym::u128
2489+
| sym::f16
2490+
| sym::f32
2491+
| sym::f64
2492+
| sym::f128
2493+
| sym::char
2494+
| sym::bool
2495+
)
2496+
}
24682497
}
24692498

24702499
/// A pattern type pattern.

compiler/rustc_ast/src/tokenstream.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ impl TokenTree {
5757
match (self, other) {
5858
(TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind,
5959
(TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => {
60-
delim == delim2 && tts.eq_unspanned(tts2)
60+
delim == delim2
61+
&& tts.len() == tts2.len()
62+
&& tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b))
6163
}
6264
_ => false,
6365
}
@@ -694,18 +696,6 @@ impl TokenStream {
694696
TokenStreamIter::new(self)
695697
}
696698

697-
/// Compares two `TokenStream`s, checking equality without regarding span information.
698-
pub fn eq_unspanned(&self, other: &TokenStream) -> bool {
699-
let mut iter1 = self.iter();
700-
let mut iter2 = other.iter();
701-
for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) {
702-
if !tt1.eq_unspanned(tt2) {
703-
return false;
704-
}
705-
}
706-
iter1.next().is_none() && iter2.next().is_none()
707-
}
708-
709699
/// Create a token stream containing a single token with alone spacing. The
710700
/// spacing used for the final token in a constructed stream doesn't matter
711701
/// because it's never used. In practice we arbitrarily use

compiler/rustc_ast/src/visit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ pub enum LifetimeCtxt {
121121
/// explicitly, you need to override each method. (And you also need
122122
/// to monitor future changes to `Visitor` in case a new method with a
123123
/// new default implementation gets introduced.)
124+
///
125+
/// Every `walk_*` method uses deconstruction to access fields of structs and
126+
/// enums. This will result in a compile error if a field is added, which makes
127+
/// it more likely the appropriate visit call will be added for it.
124128
pub trait Visitor<'ast>: Sized {
125129
/// The result type of the `visit_*` methods. Can be either `()`,
126130
/// or `ControlFlow<T>`.

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::assert_matches::assert_matches;
21
use std::ops::ControlFlow;
32
use std::sync::Arc;
43

@@ -1199,11 +1198,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
11991198
let closure_def_id = self.local_def_id(closure_id);
12001199
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
12011200

1202-
assert_matches!(
1203-
coroutine_kind,
1204-
CoroutineKind::Async { .. },
1205-
"only async closures are supported currently"
1206-
);
1201+
let coroutine_desugaring = match coroutine_kind {
1202+
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
1203+
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
1204+
CoroutineKind::AsyncGen { span, .. } => {
1205+
span_bug!(span, "only async closures and `iter!` closures are supported currently")
1206+
}
1207+
};
12071208

12081209
let body = self.with_new_scopes(fn_decl_span, |this| {
12091210
let inner_decl =
@@ -1247,7 +1248,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12471248
// Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
12481249
// knows that a `FnDecl` output type like `-> &str` actually means
12491250
// "coroutine that returns &str", rather than directly returning a `&str`.
1250-
kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
1251+
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
12511252
constness: hir::Constness::NotConst,
12521253
});
12531254
hir::ExprKind::Closure(c)

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
477477
for span in spans {
478478
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
479479
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
480+
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
480481
{
481482
#[allow(rustc::untranslatable_diagnostic)]
482-
// Don't know which of the two features to include in the
483-
// error message, so I am arbitrarily picking one.
484-
feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
483+
// Emit yield_expr as the error, since that will be sufficient. You can think of it
484+
// as coroutines and gen_blocks imply yield_expr.
485+
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
485486
.emit();
486487
}
487488
}

0 commit comments

Comments
 (0)