Auto merge of #142358 - matthiaskrgr:rollup-fxe6m7k, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#141967 (Configure bootstrap backport nominations through triagebot)
 - rust-lang/rust#142042 (Make E0621 missing lifetime suggestion verbose)
 - rust-lang/rust#142272 (tests: Change ABIs in tests to more future-resilient ones)
 - rust-lang/rust#142282 (Only run `citool` tests on the `auto` branch)
 - rust-lang/rust#142297 (Implement `//@ needs-target-std` compiletest directive)
 - rust-lang/rust#142298 (Make loongarch-none target maintainers more easily pingable)
 - rust-lang/rust#142306 (Dont unwrap and re-wrap typing envs)
 - rust-lang/rust#142324 (Remove unneeded `FunctionCx` from some codegen methods)
 - rust-lang/rust#142328 (feat: Add `bit_width` for unsigned integer types)

Failed merges:

 - rust-lang/rust#141639 (Expose discriminant values in stable_mir)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-06-11 17:51:57 +00:00
55 changed files with 400 additions and 234 deletions

View File

@@ -64,12 +64,18 @@ jobs:
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
workspaces: src/ci/citool
- name: Test citool
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
# on PR/try builds.
if: ${{ github.ref == 'refs/heads/auto' }}
run: |
cd src/ci/citool
CARGO_INCREMENTAL=0 cargo test
- name: Calculate the CI job matrix
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
cd src/ci/citool
CARGO_INCREMENTAL=0 cargo test
CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
id: jobs
job:

View File

@@ -278,7 +278,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
{
let from_backend_ty = bx.backend_type(operand.layout);
let to_backend_ty = bx.backend_type(cast);
Some(OperandValue::Immediate(self.transmute_immediate(
Some(OperandValue::Immediate(transmute_immediate(
bx,
imm,
from_scalar,
@@ -303,8 +303,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
Some(OperandValue::Pair(
self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
))
} else {
None
@@ -332,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// valid ranges. For example, `char`s are passed as just `i32`, with no
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
// the range of the input value too, not just the output range.
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
@@ -365,98 +365,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(imm)
}
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
/// or an [`OperandValue::Pair`] to an immediate of the target type.
///
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
/// `i8`, not `i1`, for `bool`-like types.)
fn transmute_immediate(
&self,
bx: &mut Bx,
mut imm: Bx::Value,
from_scalar: abi::Scalar,
from_backend_ty: Bx::Type,
to_scalar: abi::Scalar,
to_backend_ty: Bx::Type,
) -> Bx::Value {
assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
// While optimizations will remove no-op transmutes, they might still be
// there in debug or things that aren't no-op in MIR because they change
// the Rust type but not the underlying layout/niche.
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
return imm;
}
use abi::Primitive::*;
imm = bx.from_immediate(imm);
// If we have a scalar, we must already know its range. Either
//
// 1) It's a parameter with `range` parameter metadata,
// 2) It's something we `load`ed with `!range` metadata, or
// 3) After a transmute we `assume`d the range (see below).
//
// That said, last time we tried removing this, it didn't actually help
// the rustc-perf results, so might as well keep doing it
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
bx.ptrtoint(imm, to_backend_ty)
}
(Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
}
(Pointer(..), Float(_)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty)
}
};
// This `assume` remains important for cases like (a conceptual)
// transmute::<u32, NonZeroU32>(x) == 0
// since it's never passed to something with parameter metadata (especially
// after MIR inlining) so the only way to tell the backend about the
// constraint that the `transmute` introduced is to `assume` it.
self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
imm = bx.to_immediate_scalar(imm, to_scalar);
imm
}
fn assume_scalar_range(
&self,
bx: &mut Bx,
imm: Bx::Value,
scalar: abi::Scalar,
backend_ty: Bx::Type,
) {
if matches!(self.cx.sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(self.cx) {
return;
}
match scalar.primitive() {
abi::Primitive::Int(..) => {
let range = scalar.valid_range(self.cx);
bx.assume_integer_range(imm, backend_ty, range);
}
abi::Primitive::Pointer(abi::AddressSpace::DATA)
if !scalar.valid_range(self.cx).contains(0) =>
{
bx.assume_nonnull(imm);
}
abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
}
}
pub(crate) fn codegen_rvalue_unsized(
&mut self,
bx: &mut Bx,
@@ -1231,3 +1139,93 @@ impl OperandValueKind {
})
}
}
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
/// or an [`OperandValue::Pair`] to an immediate of the target type.
///
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
/// `i8`, not `i1`, for `bool`-like types.)
fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
mut imm: Bx::Value,
from_scalar: abi::Scalar,
from_backend_ty: Bx::Type,
to_scalar: abi::Scalar,
to_backend_ty: Bx::Type,
) -> Bx::Value {
assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx()));
// While optimizations will remove no-op transmutes, they might still be
// there in debug or things that aren't no-op in MIR because they change
// the Rust type but not the underlying layout/niche.
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
return imm;
}
use abi::Primitive::*;
imm = bx.from_immediate(imm);
// If we have a scalar, we must already know its range. Either
//
// 1) It's a parameter with `range` parameter metadata,
// 2) It's something we `load`ed with `!range` metadata, or
// 3) After a transmute we `assume`d the range (see below).
//
// That said, last time we tried removing this, it didn't actually help
// the rustc-perf results, so might as well keep doing it
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
(Pointer(..), Int(..)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
bx.ptrtoint(imm, to_backend_ty)
}
(Float(_), Pointer(..)) => {
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
}
(Pointer(..), Float(_)) => {
// FIXME: this exposes the provenance, which shouldn't be necessary.
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
bx.bitcast(int_imm, to_backend_ty)
}
};
// This `assume` remains important for cases like (a conceptual)
// transmute::<u32, NonZeroU32>(x) == 0
// since it's never passed to something with parameter metadata (especially
// after MIR inlining) so the only way to tell the backend about the
// constraint that the `transmute` introduced is to `assume` it.
assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
imm = bx.to_immediate_scalar(imm, to_scalar);
imm
}
fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
imm: Bx::Value,
scalar: abi::Scalar,
backend_ty: Bx::Type,
) {
if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) {
return;
}
match scalar.primitive() {
abi::Primitive::Int(..) => {
let range = scalar.valid_range(bx.cx());
bx.assume_integer_range(imm, backend_ty, range);
}
abi::Primitive::Pointer(abi::AddressSpace::DATA)
if !scalar.valid_range(bx.cx()).contains(0) =>
{
bx.assume_nonnull(imm);
}
abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
}
}

View File

@@ -389,6 +389,7 @@ tcx_lifetime! {
rustc_middle::ty::layout::FnAbiError,
rustc_middle::ty::layout::LayoutError,
rustc_middle::ty::ParamEnv,
rustc_middle::ty::TypingEnv,
rustc_middle::ty::Predicate,
rustc_middle::ty::SymbolName,
rustc_middle::ty::TraitRef,

View File

@@ -1566,7 +1566,7 @@ rustc_queries! {
/// Like `param_env`, but returns the `ParamEnv` after all opaque types have been
/// replaced with their hidden type. This is used in the old trait solver
/// when in `PostAnalysis` mode and should not be called directly.
query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> {
query typing_env_normalized_for_post_analysis(def_id: DefId) -> ty::TypingEnv<'tcx> {
desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
}

View File

@@ -1116,10 +1116,7 @@ impl<'tcx> TypingEnv<'tcx> {
}
pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
TypingEnv {
typing_mode: TypingMode::PostAnalysis,
param_env: tcx.param_env_normalized_for_post_analysis(def_id),
}
tcx.typing_env_normalized_for_post_analysis(def_id)
}
/// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
@@ -1133,7 +1130,7 @@ impl<'tcx> TypingEnv<'tcx> {
// No need to reveal opaques with the new solver enabled,
// since we have lazy norm.
let param_env = if tcx.next_trait_solver_globally() {
ParamEnv::new(param_env.caller_bounds())
param_env
} else {
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
};

View File

@@ -759,7 +759,8 @@ pub enum ExplicitLifetimeRequired<'a> {
#[suggestion(
trait_selection_explicit_lifetime_required_sugg_with_ident,
code = "{new_ty}",
applicability = "unspecified"
applicability = "unspecified",
style = "verbose"
)]
new_ty_span: Span,
#[skip_arg]
@@ -774,7 +775,8 @@ pub enum ExplicitLifetimeRequired<'a> {
#[suggestion(
trait_selection_explicit_lifetime_required_sugg_with_param_type,
code = "{new_ty}",
applicability = "unspecified"
applicability = "unspecified",
style = "verbose"
)]
new_ty_span: Span,
#[skip_arg]
@@ -1462,7 +1464,8 @@ pub enum SuggestAccessingField<'a> {
#[suggestion(
trait_selection_suggest_accessing_field,
code = "{snippet}.{name}",
applicability = "maybe-incorrect"
applicability = "maybe-incorrect",
style = "verbose"
)]
Safe {
#[primary_span]
@@ -1474,7 +1477,8 @@ pub enum SuggestAccessingField<'a> {
#[suggestion(
trait_selection_suggest_accessing_field,
code = "unsafe {{ {snippet}.{name} }}",
applicability = "maybe-incorrect"
applicability = "maybe-incorrect",
style = "verbose"
)]
Unsafe {
#[primary_span]

View File

@@ -255,10 +255,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
}
}
fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// This is a bit ugly but the easiest way to avoid code duplication.
let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
typing_env.with_post_analysis_normalized(tcx).param_env
fn typing_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TypingEnv<'_> {
ty::TypingEnv::non_body_analysis(tcx, def_id).with_post_analysis_normalized(tcx)
}
/// Check if a function is async.
@@ -374,7 +372,7 @@ pub(crate) fn provide(providers: &mut Providers) {
asyncness,
adt_sized_constraint,
param_env,
param_env_normalized_for_post_analysis,
typing_env_normalized_for_post_analysis,
defaultness,
unsizing_params_for_adt,
impl_self_is_guaranteed_unsized,

View File

@@ -213,6 +213,30 @@ macro_rules! uint_impl {
(!self).trailing_zeros()
}
/// Returns the minimum number of bits required to represent `self`.
///
/// This method returns zero if `self` is zero.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(uint_bit_width)]
///
#[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".bit_width(), 0);")]
#[doc = concat!("assert_eq!(0b111_", stringify!($SelfT), ".bit_width(), 3);")]
#[doc = concat!("assert_eq!(0b1110_", stringify!($SelfT), ".bit_width(), 4);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.bit_width(), ", stringify!($BITS), ");")]
/// ```
#[unstable(feature = "uint_bit_width", issue = "142326")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
pub const fn bit_width(self) -> u32 {
Self::BITS - self.leading_zeros()
}
/// Returns `self` with only the most significant bit set, or `0` if
/// the input is `0`.
///

View File

@@ -94,6 +94,7 @@
#![feature(try_blocks)]
#![feature(try_find)]
#![feature(try_trait_v2)]
#![feature(uint_bit_width)]
#![feature(unsize)]
#![feature(unwrap_infallible)]
// tidy-alphabetical-end

View File

@@ -72,6 +72,14 @@ macro_rules! uint_module {
assert_eq_const_safe!(u32: X.trailing_ones(), 0);
}
fn test_bit_width() {
assert_eq_const_safe!(u32: A.bit_width(), 6);
assert_eq_const_safe!(u32: B.bit_width(), 6);
assert_eq_const_safe!(u32: C.bit_width(), 7);
assert_eq_const_safe!(u32: _0.bit_width(), 0);
assert_eq_const_safe!(u32: _1.bit_width(), $T::BITS);
}
fn test_rotate() {
assert_eq_const_safe!($T: A.rotate_left(6).rotate_right(2).rotate_right(4), A);
assert_eq_const_safe!($T: B.rotate_left(3).rotate_left(2).rotate_right(5), B);

View File

@@ -84,7 +84,7 @@ pub struct Target {
impl Target {
pub fn from_triple(triple: &str) -> Self {
let mut target: Self = Default::default();
if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
if !build_helper::targets::target_supports_std(triple) {
target.no_std = true;
}
if triple.contains("emscripten") {

View File

@@ -6,6 +6,7 @@ pub mod fs;
pub mod git;
pub mod metrics;
pub mod stage0_parser;
pub mod targets;
pub mod util;
/// The default set of crates for opt-dist to collect LLVM profiles.

View File

@@ -0,0 +1,11 @@
// FIXME(#142296): this hack is because there is no reliable way (yet) to determine whether a given
// target supports std. In the long-term, we should try to implement a way to *reliably* determine
// target (std) metadata.
//
// NOTE: this is pulled out to `build_helpers` to share this hack between `bootstrap` and
// `compiletest`.
pub fn target_supports_std(target_tuple: &str) -> bool {
!(target_tuple.contains("-none")
|| target_tuple.contains("nvptx")
|| target_tuple.contains("switch"))
}

View File

@@ -202,6 +202,7 @@ settings:
`//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored
on `wasm32-unknown-unknown` target because the target does not support the
`proc-macro` crate type.
- `needs-target-std` — ignores if target platform does not have std support.
The following directives will check LLVM support:

View File

@@ -11,8 +11,8 @@ Freestanding/bare-metal LoongArch binaries in ELF format: firmware, kernels, etc
## Target maintainers
- [@heiher](https://github.com/heiher)
- [@xen0n](https://github.com/xen0n)
[@heiher](https://github.com/heiher)
[@xen0n](https://github.com/xen0n)
## Requirements

View File

@@ -166,6 +166,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"needs-subprocess",
"needs-symlink",
"needs-target-has-atomic",
"needs-target-std",
"needs-threads",
"needs-unwind",
"needs-wasmtime",

View File

@@ -174,6 +174,11 @@ pub(super) fn handle_needs(
condition: config.with_std_debug_assertions,
ignore_reason: "ignored if std wasn't built with debug assertions",
},
Need {
name: "needs-target-std",
condition: build_helper::targets::target_supports_std(&config.target),
ignore_reason: "ignored if target does not support std",
},
];
let (name, rest) = match ln.split_once([':', ' ']) {

View File

@@ -945,3 +945,14 @@ fn test_ignore_auxiliary() {
let config = cfg().build();
assert!(check_ignore(&config, "//@ ignore-auxiliary"));
}
#[test]
fn test_needs_target_std() {
// Cherry-picks two targets:
// 1. `x86_64-unknown-none`: Tier 2, intentionally never supports std.
// 2. `x86_64-unknown-linux-gnu`: Tier 1, always supports std.
let config = cfg().target("x86_64-unknown-none").build();
assert!(check_ignore(&config, "//@ needs-target-std"));
let config = cfg().target("x86_64-unknown-linux-gnu").build();
assert!(!check_ignore(&config, "//@ needs-target-std"));
}

View File

@@ -19,7 +19,7 @@
// gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
// gdb-command:whatis generic_struct2
// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "system" fn(isize) -> usize>
// gdb-command:whatis mod_struct
// gdb-check:type = type_names::mod1::Struct2
@@ -379,7 +379,7 @@ fn main() {
let simple_struct = Struct1;
let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> =
GenericStruct(PhantomData);
let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> =
let generic_struct2: GenericStruct<Struct1, extern "system" fn(isize) -> usize> =
GenericStruct(PhantomData);
let mod_struct = mod1::Struct2;

View File

@@ -440,7 +440,7 @@ trait TraitAddExternModifier {
// Change extern "C" to extern "stdcall"
#[cfg(any(cfail1,cfail4))]
trait TraitChangeExternCToRustIntrinsic {
trait TraitChangeExternCToExternSystem {
// --------------------------------------------------------------
// -------------------------
// --------------------------------------------------------------
@@ -458,7 +458,7 @@ trait TraitChangeExternCToRustIntrinsic {
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
extern "stdcall" fn method();
extern "system" fn method();
}

View File

@@ -6,15 +6,11 @@
//@ ignore-cross-compile
// Reason: the compiled binary is executed
//@ ignore-none
// Reason: no-std is not supported.
//@ ignore-wasm32
//@ ignore-wasm64
// Reason: compiling C++ to WASM may cause problems.
// Neither of these are tested in full CI.
//@ ignore-nvptx64-nvidia-cuda
// Reason: can't find crate "std"
// Not exercised in full CI, but sgx technically supports std.
//@ ignore-sgx
use run_make_support::{build_native_static_lib_cxx, run, rustc};

View File

@@ -10,8 +10,7 @@
// (See #85673)
//@ ignore-wasm32
//@ ignore-wasm64
//@ ignore-none
// Reason: no-std is not supported
//@ needs-target-std
use run_make_support::{bin_name, llvm_readobj, rustc};

View File

@@ -5,10 +5,7 @@
// source file from disk during compilation of a downstream crate.
// See https://github.com/rust-lang/rust/issues/86480
//@ ignore-none
// Reason: no-std is not supported
//@ ignore-nvptx64-nvidia-cuda
// Reason: can't find crate for 'std'
//@ needs-target-std
use run_make_support::{rfs, rust_lib_name, rustc};

View File

@@ -7,11 +7,7 @@
// was hashed by rustc in addition to the span length, and the fix still
// works.
//@ ignore-none
// reason: no-std is not supported
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for `std`
//@ needs-target-std
use run_make_support::{rfs, rustc};

View File

@@ -9,10 +9,7 @@
// for successful compilation.
// See https://github.com/rust-lang/rust/issues/83112
//@ ignore-none
// Reason: no-std is not supported
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for 'std'
//@ needs-target-std
use run_make_support::{rfs, rustc};

View File

@@ -12,10 +12,7 @@
// sessions.
// See https://github.com/rust-lang/rust/issues/85019
//@ ignore-none
// Reason: no-std is not supported
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for 'std'
//@ needs-target-std
use run_make_support::{rfs, rust_lib_name, rustc};

View File

@@ -1,4 +1,4 @@
#![feature(abi_vectorcall)]
#![feature(rust_cold_cc)]
//@ is "$.index[?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\"
pub type AbiRust = fn();
@@ -15,8 +15,5 @@ pub type AbiCUnwind = extern "C-unwind" fn();
//@ is "$.index[?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}'
pub type AbiSystemUnwind = extern "system-unwind" fn();
//@ is "$.index[?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""'
pub type AbiVecorcall = extern "vectorcall" fn();
//@ is "$.index[?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""'
pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn();
//@ is "$.index[?(@.name=='AbiRustCold')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"rust-cold\""'
pub type AbiRustCold = extern "rust-cold" fn();

View File

@@ -1,4 +1,4 @@
#![feature(abi_vectorcall)]
#![feature(rust_cold_cc)]
//@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\"
pub fn abi_rust() {}
@@ -15,8 +15,5 @@ pub extern "C-unwind" fn abi_c_unwind() {}
//@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
pub extern "system-unwind" fn abi_system_unwind() {}
//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
pub extern "vectorcall" fn abi_vectorcall() {}
//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
//@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
pub extern "rust-cold" fn abi_rust_cold() {}

View File

@@ -1,5 +1,4 @@
#![feature(abi_vectorcall)]
#![feature(rust_cold_cc)]
//@ has "$.index[?(@.name=='Foo')]"
pub struct Foo;
@@ -19,11 +18,8 @@ impl Foo {
//@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
pub extern "system-unwind" fn abi_system_unwind() {}
//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
pub extern "vectorcall" fn abi_vectorcall() {}
//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
//@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
pub extern "rust-cold" fn abi_rust_cold() {}
}
pub trait Bar {
@@ -42,9 +38,6 @@ pub trait Bar {
//@ is "$.index[?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
extern "system-unwind" fn trait_abi_system_unwind() {}
//@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
extern "vectorcall" fn trait_abi_vectorcall() {}
//@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {}
//@ is "$.index[?(@.name=='trait_abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
extern "rust-cold" fn trait_abi_rust_cold() {}
}

View File

@@ -0,0 +1,27 @@
#![feature(abi_vectorcall)]
//@ only-x86_64
//@ is "$.index[?(@.name=='AbiVectorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""'
pub type AbiVectorcall = extern "vectorcall" fn();
//@ is "$.index[?(@.name=='AbiVectorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""'
pub type AbiVectorcallUnwind = extern "vectorcall-unwind" fn();
//@ has "$.index[?(@.name=='Foo')]"
pub struct Foo;
impl Foo {
//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
pub extern "vectorcall" fn abi_vectorcall() {}
//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
}
pub trait Bar {
//@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
extern "vectorcall" fn trait_abi_vectorcall() {}
//@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {}
}

View File

@@ -106,11 +106,13 @@ LL | }
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/without-precise-captures-we-are-powerless.rs:38:5
|
LL | fn through_field_and_ref<'a>(x: &S<'a>) {
| ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
...
LL | outlives::<'a>(call_once(c));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn through_field_and_ref<'a>(x: &'a S<'a>) {
| ++
error[E0597]: `c` does not live long enough
--> $DIR/without-precise-captures-we-are-powerless.rs:43:20
@@ -131,11 +133,13 @@ LL | }
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/without-precise-captures-we-are-powerless.rs:44:5
|
LL | fn through_field_and_ref_move<'a>(x: &S<'a>) {
| ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
...
LL | outlives::<'a>(call_once(c));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn through_field_and_ref_move<'a>(x: &'a S<'a>) {
| ++
error: aborting due to 10 previous errors

View File

@@ -1,11 +1,14 @@
error[E0621]: explicit lifetime required in the type of `foo`
--> $DIR/issue-63388-1.rs:14:9
|
LL | &'a self, foo: &dyn Foo
| -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
...
LL | foo
| ^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `foo`
|
LL - &'a self, foo: &dyn Foo
LL + &'a self, foo: &'a (dyn Foo + 'a)
|
error: aborting due to 1 previous error

View File

@@ -65,9 +65,12 @@ error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/must_outlive_least_region_or_bound.rs:15:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ++
error: lifetime may not live long enough
--> $DIR/must_outlive_least_region_or_bound.rs:30:55

View File

@@ -1,11 +1,13 @@
error[E0621]: explicit lifetime required in the type of `cont`
--> $DIR/issue-13058.rs:14:21
|
LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
| -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T`
LL | {
LL | let cont_iter = cont.iter();
| ^^^^^^^^^^^ lifetime `'r` required
|
help: add explicit lifetime `'r` to the type of `cont`
|
LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &'r T) -> bool
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,14 @@
error[E0621]: explicit lifetime required in the type of `a`
--> $DIR/issue-14285.rs:12:5
|
LL | fn foo<'a>(a: &dyn Foo) -> B<'a> {
| -------- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)`
LL | B(a)
| ^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `a`
|
LL - fn foo<'a>(a: &dyn Foo) -> B<'a> {
LL + fn foo<'a>(a: &'a (dyn Foo + 'a)) -> B<'a> {
|
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `lexer`
--> $DIR/issue-15034.rs:17:9
|
LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> {
| ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>`
LL | Parser { lexer: lexer }
| ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `lexer`
|
LL | pub fn new(lexer: &'a mut Lexer<'a>) -> Parser<'a> {
| ++++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/issue-3154.rs:6:5
|
LL | fn thing<'a,Q>(x: &Q) -> Thing<'a,Q> {
| -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q`
LL | Thing { x: x }
| ^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn thing<'a,Q>(x: &'a Q) -> Thing<'a,Q> {
| ++
error: aborting due to 1 previous error

View File

@@ -1,20 +1,24 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/issue-40288-2.rs:9:5
|
LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
| -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
...
LL | out[0]
| ^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `y`
|
LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T {
| ++
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/issue-40288-2.rs:24:5
|
LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
| -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
...
LL | out.head
| ^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `y`
|
LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T {
| ++
error: aborting due to 2 previous errors

View File

@@ -1,11 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/42701_one_named_and_one_anonymous.rs:10:9
|
LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 {
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
...
LL | &*x
| ^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo2<'a>(a: &'a Foo, x: &'a i32) -> &'a i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,11 +1,13 @@
error[E0621]: explicit lifetime required in the type of `other`
--> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:11:21
|
LL | fn bar(&self, other: Foo) -> Foo<'a> {
| --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>`
...
LL | other
| ^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `other`
|
LL | fn bar(&self, other: Foo<'a>) -> Foo<'a> {
| ++++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex1-return-one-existing-name-if-else-2.rs:2:16
|
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
LL | if x > y { x } else { y }
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in parameter type
--> $DIR/ex1-return-one-existing-name-if-else-3.rs:2:27
|
LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 {
| --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)`
LL | if x > y { x } else { y }
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to type
|
LL | fn foo<'a>((x, y): (&'a i32, &'a i32)) -> &'a i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:4:15
|
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
LL | if x > y { x } else { y }
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36
|
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
LL | if true { &self.field } else { x }
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/ex1-return-one-existing-name-if-else.rs:2:27
|
LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
| ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32`
LL | if x > y { x } else { y }
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `y`
|
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `x`
--> $DIR/ex2a-push-one-existing-name-2.rs:6:5
|
LL | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) {
| -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>`
LL | y.push(x);
| ^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `x`
|
LL | fn foo<'a>(x: Ref<'a, i32>, y: &mut Vec<Ref<'a, i32>>) {
| +++
error: aborting due to 1 previous error

View File

@@ -1,11 +1,13 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5
|
LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
| -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
...
LL | x.push(y);
| ^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `y`
|
LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &'a T)
| ++
error: aborting due to 1 previous error

View File

@@ -1,10 +1,13 @@
error[E0621]: explicit lifetime required in the type of `y`
--> $DIR/ex2a-push-one-existing-name.rs:6:5
|
LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
| -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>`
LL | x.push(y);
| ^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `y`
|
LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) {
| +++
error: aborting due to 1 previous error

View File

@@ -15,11 +15,14 @@ LL | struct Foo<'c, 'd>(&'c (), &'d ());
error[E0621]: explicit lifetime required in the type of `foo`
--> $DIR/noisy-follow-up-erro.rs:14:9
|
LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> {
| -------------------- help: add explicit lifetime `'a` to the type of `foo`: `&mut Foo<'_, 'a>`
LL |
LL | self.bar().map_err(|()| foo.acc(self))?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `foo`
|
LL - fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> {
LL + fn boom(&self, foo: &mut Foo<'_, 'a>) -> Result<(), &'a ()> {
|
error: aborting due to 2 previous errors

View File

@@ -21,11 +21,13 @@ LL | ss.r
error[E0621]: explicit lifetime required in the type of `ss`
--> $DIR/object-lifetime-default-from-box-error.rs:33:5
|
LL | fn store1<'b>(ss: &mut SomeStruct, b: Box<dyn SomeTrait+'b>) {
| --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>`
...
LL | ss.r = b;
| ^^^^ lifetime `'b` required
|
help: add explicit lifetime `'b` to the type of `ss`
|
LL | fn store1<'b>(ss: &mut SomeStruct<'b>, b: Box<dyn SomeTrait+'b>) {
| ++++
error: aborting due to 3 previous errors

View File

@@ -1,8 +1,6 @@
error[E0621]: explicit lifetime required in the type of `s`
--> $DIR/regions-glb-free-free.rs:15:13
|
LL | pub fn set_desc(self, s: &str) -> Flag<'a> {
| ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str`
LL | / Flag {
LL | | name: self.name,
LL | | desc: s,
@@ -10,6 +8,11 @@ LL | | max_count: self.max_count,
LL | | value: self.value
LL | | }
| |_____________^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `s`
|
LL | pub fn set_desc(self, s: &'a str) -> Flag<'a> {
| ++
error: aborting due to 1 previous error

View File

@@ -2,9 +2,12 @@ error[E0621]: explicit lifetime required in the type of `p`
--> $DIR/regions-infer-at-fn-not-param.rs:13:57
|
LL | fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p }
| -------------- ^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `p`: `Parameterized1<'a>`
| ^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `p`
|
LL | fn take1<'a>(p: Parameterized1<'a>) -> Parameterized1<'a> { p }
| ++++
error: aborting due to 1 previous error

View File

@@ -101,15 +101,17 @@ LL + fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b
error[E0621]: explicit lifetime required in the type of `dest`
--> $DIR/missing-lifetimes-in-signature.rs:73:5
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
| ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
...
LL | / move || {
LL | |
LL | |
LL | | *dest = g.get();
LL | | }
| |_____^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `dest`
|
LL | fn bat<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
| ++
error[E0309]: the parameter type `G` may not live long enough
--> $DIR/missing-lifetimes-in-signature.rs:85:5

View File

@@ -1,11 +1,13 @@
error[E0621]: explicit lifetime required in the type of `get`
--> $DIR/variance-trait-matching.rs:24:5
|
LL | fn get<'a, G>(get: &G) -> i32
| -- help: add explicit lifetime `'a` to the type of `get`: `&'a G`
...
LL | pick(get, &22)
| ^^^^^^^^^^^^^^ lifetime `'a` required
|
help: add explicit lifetime `'a` to the type of `get`
|
LL | fn get<'a, G>(get: &'a G) -> i32
| ++
error: aborting due to 1 previous error

View File

@@ -729,6 +729,41 @@ don't know
]
message_on_remove = "PR #{number}'s stable-nomination has been removed."
[notify-zulip."beta-nominated".bootstrap]
required_labels = ["T-bootstrap"]
zulip_stream = 507486 # #t-infra/bootstrap/backports
topic = "#{number}: beta-nominated"
message_on_add = [
"""\
@*T-bootstrap* PR #{number} "{title}" has been nominated for beta backport.
""",
"""\
/poll Approve beta backport of #{number}?
approve
decline
don't know
""",
]
message_on_remove = "PR #{number}'s beta-nomination has been removed."
[notify-zulip."stable-nominated".bootstrap]
required_labels = ["T-bootstrap"]
zulip_stream = 507486 # #t-infra/bootstrap/backports
topic = "#{number}: stable-nominated"
message_on_add = [
"""\
@*T-bootstrap* PR #{number} "{title}" has been nominated for stable backport.
""",
"""\
/poll Approve stable backport of #{number}?
approve
approve (but does not justify new dot release on its own)
decline
don't know
""",
]
message_on_remove = "PR #{number}'s stable-nomination has been removed."
[notify-zulip."A-edition-2021"]
required_labels = ["C-bug"]
zulip_stream = 268952 # #edition