mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 05:56:56 +00:00
Auto merge of #138653 - matthiaskrgr:rollup-fwwqmr7, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #136320 (exit: document interaction with C) - #138080 (Leave a breadcrumb towards bootstrap config documentation in `bootstrap.toml`) - #138301 (Implement `read_buf` for Hermit) - #138569 (rustdoc-json: Add tests for `#[repr(...)]`) - #138635 (Extract `for_each_immediate_subpat` from THIR pattern visitors) - #138642 (Unvacation myself) - #138644 (Add `#[cfg(test)]` for Transition in dfa in `rustc_transmute`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c4b38a5967
@ -28,6 +28,7 @@ use tracing::instrument;
|
||||
use crate::middle::region;
|
||||
use crate::mir::interpret::AllocId;
|
||||
use crate::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
|
||||
use crate::thir::visit::for_each_immediate_subpat;
|
||||
use crate::ty::adjustment::PointerCoercion;
|
||||
use crate::ty::layout::IntegerExt;
|
||||
use crate::ty::{
|
||||
@ -672,27 +673,7 @@ impl<'tcx> Pat<'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
use PatKind::*;
|
||||
match &self.kind {
|
||||
Wild
|
||||
| Never
|
||||
| Range(..)
|
||||
| Binding { subpattern: None, .. }
|
||||
| Constant { .. }
|
||||
| Error(_) => {}
|
||||
AscribeUserType { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern, .. }
|
||||
| ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
|
||||
Leaf { subpatterns } | Variant { subpatterns, .. } => {
|
||||
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
|
||||
}
|
||||
Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
|
||||
Array { box prefix, slice, box suffix } | Slice { box prefix, slice, box suffix } => {
|
||||
prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it))
|
||||
}
|
||||
}
|
||||
for_each_immediate_subpat(self, |p| p.walk_(it));
|
||||
}
|
||||
|
||||
/// Whether the pattern has a `PatKind::Error` nested within.
|
||||
|
@ -240,36 +240,45 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||
visitor: &mut V,
|
||||
pat: &'thir Pat<'tcx>,
|
||||
) {
|
||||
use PatKind::*;
|
||||
match &pat.kind {
|
||||
AscribeUserType { subpattern, ascription: _ }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern, .. }
|
||||
| Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
|
||||
Binding { .. } | Wild | Never | Error(_) => {}
|
||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
visitor.visit_pat(&subpattern.pattern);
|
||||
}
|
||||
}
|
||||
Constant { value: _ } => {}
|
||||
ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
|
||||
Range(_) => {}
|
||||
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
|
||||
for subpattern in prefix.iter() {
|
||||
visitor.visit_pat(subpattern);
|
||||
}
|
||||
if let Some(pat) = slice {
|
||||
visitor.visit_pat(pat);
|
||||
}
|
||||
for subpattern in suffix.iter() {
|
||||
visitor.visit_pat(subpattern);
|
||||
}
|
||||
}
|
||||
Or { pats } => {
|
||||
for pat in pats.iter() {
|
||||
visitor.visit_pat(pat);
|
||||
}
|
||||
}
|
||||
};
|
||||
for_each_immediate_subpat(pat, |p| visitor.visit_pat(p));
|
||||
}
|
||||
|
||||
/// Invokes `callback` on each immediate subpattern of `pat`, if any.
|
||||
/// A building block for assembling THIR pattern visitors.
|
||||
pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
||||
pat: &'a Pat<'tcx>,
|
||||
mut callback: impl FnMut(&'a Pat<'tcx>),
|
||||
) {
|
||||
match &pat.kind {
|
||||
PatKind::Wild
|
||||
| PatKind::Binding { subpattern: None, .. }
|
||||
| PatKind::Constant { value: _ }
|
||||
| PatKind::Range(_)
|
||||
| PatKind::Never
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::AscribeUserType { subpattern, .. }
|
||||
| PatKind::Binding { subpattern: Some(subpattern), .. }
|
||||
| PatKind::Deref { subpattern }
|
||||
| PatKind::DerefPattern { subpattern, .. }
|
||||
| PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern),
|
||||
|
||||
PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
|
||||
for field_pat in subpatterns {
|
||||
callback(&field_pat.pattern);
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Slice { prefix, slice, suffix } | PatKind::Array { prefix, slice, suffix } => {
|
||||
for pat in prefix.iter().chain(slice.as_deref()).chain(suffix) {
|
||||
callback(pat);
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Or { pats } => {
|
||||
for pat in pats {
|
||||
callback(pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ where
|
||||
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
|
||||
pub(crate) struct State(u32);
|
||||
|
||||
#[cfg(test)]
|
||||
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
|
||||
pub(crate) enum Transition<R>
|
||||
where
|
||||
@ -70,6 +71,7 @@ impl fmt::Debug for State {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<R> fmt::Debug for Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
@ -166,6 +168,7 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<R> From<nfa::Transition<R>> for Transition<R>
|
||||
where
|
||||
R: Ref,
|
||||
|
@ -333,7 +333,7 @@ impl Error for VarError {
|
||||
///
|
||||
/// Discussion of this unsafety on Unix may be found in:
|
||||
///
|
||||
/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
|
||||
/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=188)
|
||||
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
|
||||
///
|
||||
/// To pass an environment variable to a child process, you can instead use [`Command::env`].
|
||||
|
@ -2018,9 +2018,9 @@ impl ExitCode {
|
||||
///
|
||||
/// Note that this has the same caveats as [`process::exit()`][exit], namely that this function
|
||||
/// terminates the process immediately, so no destructors on the current stack or any other
|
||||
/// thread's stack will be run. If a clean shutdown is needed, it is recommended to simply
|
||||
/// return this ExitCode from the `main` function, as demonstrated in the [type
|
||||
/// documentation](#examples).
|
||||
/// thread's stack will be run. Also see those docs for some important notes on interop with C
|
||||
/// code. If a clean shutdown is needed, it is recommended to simply return this ExitCode from
|
||||
/// the `main` function, as demonstrated in the [type documentation](#examples).
|
||||
///
|
||||
/// # Differences from `process::exit()`
|
||||
///
|
||||
@ -2326,6 +2326,33 @@ impl Child {
|
||||
///
|
||||
/// process::exit(0x0100);
|
||||
/// ```
|
||||
///
|
||||
/// ### Safe interop with C code
|
||||
///
|
||||
/// On Unix, this function is currently implemented using the `exit` C function [`exit`][C-exit]. As
|
||||
/// of C23, the C standard does not permit multiple threads to call `exit` concurrently. Rust
|
||||
/// mitigates this with a lock, but if C code calls `exit`, that can still cause undefined behavior.
|
||||
/// Note that returning from `main` is equivalent to calling `exit`.
|
||||
///
|
||||
/// Therefore, it is undefined behavior to have two concurrent threads perform the following
|
||||
/// without synchronization:
|
||||
/// - One thread calls Rust's `exit` function or returns from Rust's `main` function
|
||||
/// - Another thread calls the C function `exit` or `quick_exit`, or returns from C's `main` function
|
||||
///
|
||||
/// Note that if a binary contains multiple copies of the Rust runtime (e.g., when combining
|
||||
/// multiple `cdylib` or `staticlib`), they each have their own separate lock, so from the
|
||||
/// perspective of code running in one of the Rust runtimes, the "outside" Rust code is basically C
|
||||
/// code, and concurrent `exit` again causes undefined behavior.
|
||||
///
|
||||
/// Individual C implementations might provide more guarantees than the standard and permit concurrent
|
||||
/// calls to `exit`; consult the documentation of your C implementation for details.
|
||||
///
|
||||
/// For some of the on-going discussion to make `exit` thread-safe in C, see:
|
||||
/// - [Rust issue #126600](https://github.com/rust-lang/rust/issues/126600)
|
||||
/// - [Austin Group Bugzilla (for POSIX)](https://austingroupbugs.net/view.php?id=1845)
|
||||
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=31997)
|
||||
///
|
||||
/// [C-exit]: https://en.cppreference.com/w/c/program/exit
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "process_exit")]
|
||||
pub fn exit(code: i32) -> ! {
|
||||
|
@ -396,7 +396,7 @@ impl File {
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
crate::io::default_read_buf(|buf| self.read(buf), cursor)
|
||||
self.0.read_buf(cursor)
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use super::hermit_abi;
|
||||
use crate::cmp;
|
||||
use crate::io::{self, IoSlice, IoSliceMut, Read, SeekFrom};
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom};
|
||||
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
use crate::sys::{cvt, unsupported};
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner};
|
||||
@ -23,6 +23,21 @@ impl FileDesc {
|
||||
Ok(result as usize)
|
||||
}
|
||||
|
||||
pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
// SAFETY: The `read` syscall does not read from the buffer, so it is
|
||||
// safe to use `&mut [MaybeUninit<u8>]`.
|
||||
let result = cvt(unsafe {
|
||||
hermit_abi::read(
|
||||
self.fd.as_raw_fd(),
|
||||
buf.as_mut().as_mut_ptr() as *mut u8,
|
||||
buf.capacity(),
|
||||
)
|
||||
})?;
|
||||
// SAFETY: Exactly `result` bytes have been filled.
|
||||
unsafe { buf.advance_unchecked(result as usize) };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
hermit_abi::readv(
|
||||
|
@ -3,9 +3,7 @@ use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||
#[cfg(target_family = "unix")]
|
||||
use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
use crate::io::BorrowedCursor;
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
|
||||
use crate::mem::ManuallyDrop;
|
||||
#[cfg(target_os = "hermit")]
|
||||
use crate::os::hermit::io::FromRawFd;
|
||||
@ -28,7 +26,6 @@ impl io::Read for Stdin {
|
||||
unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) }
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "hermit"))]
|
||||
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> {
|
||||
unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) }
|
||||
}
|
||||
|
@ -214,8 +214,9 @@ fn setup_config_toml(path: &Path, profile: Profile, config: &Config) {
|
||||
|
||||
let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
|
||||
let settings = format!(
|
||||
"# Includes one of the default files in {PROFILE_DIR}\n\
|
||||
profile = \"{profile}\"\n\
|
||||
"# See bootstrap.example.toml for documentation of available options\n\
|
||||
#\n\
|
||||
profile = \"{profile}\" # Includes one of the default files in {PROFILE_DIR}\n\
|
||||
change-id = {latest_change_id}\n"
|
||||
);
|
||||
|
||||
|
8
tests/rustdoc-json/attrs/repr_align.rs
Normal file
8
tests/rustdoc-json/attrs/repr_align.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[*][?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]'
|
||||
#[repr(align(4))]
|
||||
pub struct Aligned {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
18
tests/rustdoc-json/attrs/repr_c.rs
Normal file
18
tests/rustdoc-json/attrs/repr_c.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]'
|
||||
#[repr(C)]
|
||||
pub struct ReprCStruct(pub i64);
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]'
|
||||
#[repr(C)]
|
||||
pub enum ReprCEnum {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]'
|
||||
#[repr(C)]
|
||||
pub union ReprCUnion {
|
||||
pub left: i64,
|
||||
pub right: u64,
|
||||
}
|
78
tests/rustdoc-json/attrs/repr_combination.rs
Normal file
78
tests/rustdoc-json/attrs/repr_combination.rs
Normal file
@ -0,0 +1,78 @@
|
||||
#![no_std]
|
||||
|
||||
// Combinations of `#[repr(..)]` attributes.
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]'
|
||||
#[repr(C, i8)]
|
||||
pub enum ReprCI8 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]'
|
||||
#[repr(C)]
|
||||
#[repr(i16)]
|
||||
pub enum SeparateReprCI16 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]'
|
||||
#[repr(usize, C)]
|
||||
pub enum ReversedReprCUsize {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]'
|
||||
#[repr(C, packed)]
|
||||
pub struct ReprCPacked {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]'
|
||||
#[repr(C)]
|
||||
#[repr(packed(2))]
|
||||
pub struct SeparateReprCPacked {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]'
|
||||
#[repr(packed(2), C)]
|
||||
pub struct ReversedReprCPacked {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]'
|
||||
#[repr(C, align(16))]
|
||||
pub struct ReprCAlign {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]'
|
||||
#[repr(C)]
|
||||
#[repr(align(2))]
|
||||
pub struct SeparateReprCAlign {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]'
|
||||
#[repr(align(2), C)]
|
||||
pub struct ReversedReprCAlign {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]'
|
||||
#[repr(C, align(16), isize)]
|
||||
pub enum AlignedExplicitRepr {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]'
|
||||
#[repr(isize, C, align(16))]
|
||||
pub enum ReorderedAlignedExplicitRepr {
|
||||
First,
|
||||
}
|
19
tests/rustdoc-json/attrs/repr_int_enum.rs
Normal file
19
tests/rustdoc-json/attrs/repr_int_enum.rs
Normal file
@ -0,0 +1,19 @@
|
||||
#![no_std]
|
||||
|
||||
//@ is "$.index[*][?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]'
|
||||
#[repr(i8)]
|
||||
pub enum I8 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
|
||||
#[repr(i32)]
|
||||
pub enum I32 {
|
||||
First,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]'
|
||||
#[repr(usize)]
|
||||
pub enum Usize {
|
||||
First,
|
||||
}
|
18
tests/rustdoc-json/attrs/repr_packed.rs
Normal file
18
tests/rustdoc-json/attrs/repr_packed.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![no_std]
|
||||
|
||||
// Note the normalization:
|
||||
// `#[repr(packed)]` in has the implict "1" in rustdoc JSON.
|
||||
|
||||
//@ is "$.index[*][?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]'
|
||||
#[repr(packed)]
|
||||
pub struct Packed {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
||||
|
||||
//@ is "$.index[*][?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]'
|
||||
#[repr(packed(4))]
|
||||
pub struct PackedAligned {
|
||||
a: i8,
|
||||
b: i64,
|
||||
}
|
22
tests/rustdoc-json/attrs/repr_transparent.rs
Normal file
22
tests/rustdoc-json/attrs/repr_transparent.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#![no_std]
|
||||
|
||||
// Rustdoc JSON currently includes `#[repr(transparent)]`
|
||||
// even if the transparency is not part of the public API
|
||||
//
|
||||
// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
|
||||
|
||||
//@ is "$.index[*][?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
|
||||
#[repr(transparent)]
|
||||
pub struct Transparent(pub i64);
|
||||
|
||||
//@ is "$.index[*][?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
|
||||
#[repr(transparent)]
|
||||
pub struct TransparentNonPub(i64);
|
||||
|
||||
//@ is "$.index[*][?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
|
||||
#[repr(transparent)]
|
||||
pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ());
|
||||
|
||||
//@ is "$.index[*][?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
|
||||
#[repr(transparent)]
|
||||
pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ());
|
@ -1082,7 +1082,6 @@ contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
|
||||
users_on_vacation = [
|
||||
"jyn514",
|
||||
"ChrisDenton",
|
||||
"jieyouxu",
|
||||
]
|
||||
|
||||
[[assign.warn_non_default_branch.exceptions]]
|
||||
|
Loading…
Reference in New Issue
Block a user