Auto merge of #86791 - JohnTitor:rollup-96ltzpz, r=JohnTitor

Rollup of 7 pull requests

Successful merges:

 - #86148 (Check the number of generic lifetime and const parameters of intrinsics)
 - #86659 (fix(rustdoc): generics search)
 - #86768 (Add myself to mailmap)
 - #86775 (Test for const trait impls behind feature gates)
 - #86779 (Allow anyone to add or remove any label starting with perf-)
 - #86783 (Move Mutex::unlock to T: ?Sized)
 - #86785 (proc_macro/bridge: Remove dead code Slice type)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-07-01 21:45:19 +00:00
commit 56dee7c49e
25 changed files with 391 additions and 123 deletions

View file

@ -72,6 +72,7 @@ Daniel Ramos <dan@daramos.com>
David Klein <david.klein@baesystemsdetica.com>
David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
David Ross <daboross@daboross.net>
Deadbeef <ent3rm4n@gmail.com> <fee1-dead-beef@protonmail.com>
Derek Chiang <derekchiang93@gmail.com> Derek Chiang (Enchi Jiang) <derekchiang93@gmail.com>
Diggory Hardy <diggory.hardy@gmail.com> Diggory Hardy <github@dhardy.name>
Donough Liu <ldm2993593805@163.com> <donoughliu@gmail.com>

View file

@ -1,4 +1,4 @@
An invalid number of type parameters was given to an intrinsic function.
An invalid number of generic parameters was passed to an intrinsic function.
Erroneous code example:

View file

@ -3,11 +3,11 @@
use crate::errors::{
SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
WrongNumberOfTypeArgumentsToInstrinsic,
WrongNumberOfGenericArgumentsToIntrinsic,
};
use crate::require_same_types;
use rustc_errors::struct_span_err;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::subst::Subst;
@ -21,36 +21,45 @@ fn equate_intrinsic_type<'tcx>(
tcx: TyCtxt<'tcx>,
it: &hir::ForeignItem<'_>,
n_tps: usize,
n_lts: usize,
sig: ty::PolyFnSig<'tcx>,
) {
match it.kind {
hir::ForeignItemKind::Fn(..) => {}
let (own_counts, span) = match &it.kind {
hir::ForeignItemKind::Fn(.., generics) => {
let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
(own_counts, generics.span)
}
_ => {
struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function")
.span_label(it.span, "expected a function")
.emit();
return;
}
};
let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool {
if found != expected {
tcx.sess.emit_err(WrongNumberOfGenericArgumentsToIntrinsic {
span,
found,
expected,
expected_pluralize: pluralize!(expected),
descr,
});
false
} else {
true
}
};
if gen_count_ok(own_counts.lifetimes, n_lts, "lifetime")
&& gen_count_ok(own_counts.types, n_tps, "type")
&& gen_count_ok(own_counts.consts, 0, "const")
{
let fty = tcx.mk_fn_ptr(sig);
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
}
let i_n_tps = tcx.generics_of(it.def_id).own_counts().types;
if i_n_tps != n_tps {
let span = match it.kind {
hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span,
_ => bug!(),
};
tcx.sess.emit_err(WrongNumberOfTypeArgumentsToInstrinsic {
span,
found: i_n_tps,
expected: n_tps,
});
return;
}
let fty = tcx.mk_fn_ptr(sig);
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
}
/// Returns the unsafety of the given intrinsic.
@ -121,7 +130,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
})
};
let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
let (n_tps, n_lts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
let split: Vec<&str> = name_str.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
@ -143,7 +152,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
return;
}
};
(n_tps, inputs, output, hir::Unsafety::Unsafe)
(n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
} else {
let unsafety = intrinsic_operation_unsafety(intrinsic_name);
let (n_tps, inputs, output) = match intrinsic_name {
@ -372,11 +381,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
return;
}
};
(n_tps, inputs, output, unsafety)
(n_tps, 0, inputs, output, unsafety)
};
let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic);
let sig = ty::Binder::bind_with_vars(sig, bound_vars);
equate_intrinsic_type(tcx, it, n_tps, sig)
equate_intrinsic_type(tcx, it, n_tps, n_lts, sig)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
@ -472,5 +481,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
Abi::PlatformIntrinsic,
);
let sig = ty::Binder::dummy(sig);
equate_intrinsic_type(tcx, it, n_tps, sig)
equate_intrinsic_type(tcx, it, n_tps, 0, sig)
}

View file

@ -24,13 +24,15 @@ pub struct UnrecognizedAtomicOperation<'a> {
#[derive(SessionDiagnostic)]
#[error = "E0094"]
pub struct WrongNumberOfTypeArgumentsToInstrinsic {
#[message = "intrinsic has wrong number of type \
pub struct WrongNumberOfGenericArgumentsToIntrinsic<'a> {
#[message = "intrinsic has wrong number of {descr} \
parameters: found {found}, expected {expected}"]
#[label = "expected {expected} type parameter"]
#[label = "expected {expected} {descr} parameter{expected_pluralize}"]
pub span: Span,
pub found: usize,
pub expected: usize,
pub expected_pluralize: &'a str,
pub descr: &'a str,
}
#[derive(SessionDiagnostic)]

View file

@ -5,35 +5,6 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use std::slice;
#[repr(C)]
struct Slice<'a, T> {
data: &'a [T; 0],
len: usize,
}
unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {}
unsafe impl<'a, T: Sync> Send for Slice<'a, T> {}
impl<T> Copy for Slice<'a, T> {}
impl<T> Clone for Slice<'a, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> From<&'a [T]> for Slice<'a, T> {
fn from(xs: &'a [T]) -> Self {
Slice { data: unsafe { &*(xs.as_ptr() as *const [T; 0]) }, len: xs.len() }
}
}
impl<T> Deref for Slice<'a, T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
}
}
#[repr(C)]
pub struct Buffer<T: Copy> {
data: *mut T,

View file

@ -217,26 +217,6 @@ impl<T> Mutex<T> {
data: UnsafeCell::new(t),
}
}
/// Immediately drops the guard, and consequently unlocks the mutex.
///
/// This function is equivalent to calling [`drop`] on the guard but is more self-documenting.
/// Alternately, the guard will be automatically dropped when it goes out of scope.
///
/// ```
/// #![feature(mutex_unlock)]
///
/// use std::sync::Mutex;
/// let mutex = Mutex::new(0);
///
/// let mut guard = mutex.lock().unwrap();
/// *guard += 20;
/// Mutex::unlock(guard);
/// ```
#[unstable(feature = "mutex_unlock", issue = "81872")]
pub fn unlock(guard: MutexGuard<'_, T>) {
drop(guard);
}
}
impl<T: ?Sized> Mutex<T> {
@ -333,6 +313,26 @@ impl<T: ?Sized> Mutex<T> {
}
}
/// Immediately drops the guard, and consequently unlocks the mutex.
///
/// This function is equivalent to calling [`drop`] on the guard but is more self-documenting.
/// Alternately, the guard will be automatically dropped when it goes out of scope.
///
/// ```
/// #![feature(mutex_unlock)]
///
/// use std::sync::Mutex;
/// let mutex = Mutex::new(0);
///
/// let mut guard = mutex.lock().unwrap();
/// *guard += 20;
/// Mutex::unlock(guard);
/// ```
#[unstable(feature = "mutex_unlock", issue = "81872")]
pub fn unlock(guard: MutexGuard<'_, T>) {
drop(guard);
}
/// Determines whether the mutex is poisoned.
///
/// If another thread is active, the mutex can still become poisoned at any

View file

@ -219,6 +219,7 @@ crate fn get_index_search_type<'tcx>(
fn get_index_type(clean_type: &clean::Type) -> RenderType {
RenderType {
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
generics: get_generics(clean_type),
}
}
@ -251,6 +252,23 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option
}
}
/// Return a list of generic parameters for use in the search index.
///
/// This function replaces bounds with types, so that `T where T: Debug` just becomes `Debug`.
/// It does return duplicates, and that's intentional, since search queries like `Result<usize, usize>`
/// are supposed to match only results where both parameters are `usize`.
fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
clean_type.generics().and_then(|types| {
let r = types
.iter()
.filter_map(|t| {
get_index_type_name(t, false).map(|name| name.as_str().to_ascii_lowercase())
})
.collect::<Vec<_>>();
if r.is_empty() { None } else { Some(r) }
})
}
/// The point of this function is to replace bounds with types.
///
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return

View file

@ -96,6 +96,7 @@ crate struct IndexItem {
#[derive(Debug)]
crate struct RenderType {
name: Option<String>,
generics: Option<Vec<String>>,
}
/// Full type of functions/methods in the search index.
@ -149,7 +150,13 @@ impl Serialize for TypeWithKind {
where
S: Serializer,
{
(&self.ty.name, self.kind).serialize(serializer)
let mut seq = serializer.serialize_seq(None)?;
seq.serialize_element(&self.ty.name)?;
seq.serialize_element(&self.kind)?;
if let Some(generics) = &self.ty.generics {
seq.serialize_element(generics)?;
}
seq.end()
}
}

View file

@ -106,7 +106,7 @@ function levenshtein(s1, s2) {
window.initSearch = function(rawSearchIndex) {
var MAX_LEV_DISTANCE = 3;
var MAX_RESULTS = 200;
var GENERICS_DATA = 1;
var GENERICS_DATA = 2;
var NAME = 0;
var INPUTS_DATA = 0;
var OUTPUT_DATA = 1;
@ -306,6 +306,9 @@ window.initSearch = function(rawSearchIndex) {
var elems = Object.create(null);
var elength = obj[GENERICS_DATA].length;
for (var x = 0; x < elength; ++x) {
if (!elems[getObjectNameFromId(obj[GENERICS_DATA][x])]) {
elems[getObjectNameFromId(obj[GENERICS_DATA][x])] = 0;
}
elems[getObjectNameFromId(obj[GENERICS_DATA][x])] += 1;
}
var total = 0;
@ -354,10 +357,13 @@ window.initSearch = function(rawSearchIndex) {
if (literalSearch) {
if (val.generics && val.generics.length !== 0) {
if (obj.length > GENERICS_DATA &&
obj[GENERICS_DATA].length >= val.generics.length) {
obj[GENERICS_DATA].length > 0) {
var elems = Object.create(null);
len = obj[GENERICS_DATA].length;
for (x = 0; x < len; ++x) {
if (!elems[getObjectNameFromId(obj[GENERICS_DATA][x])]) {
elems[getObjectNameFromId(obj[GENERICS_DATA][x])] = 0;
}
elems[getObjectNameFromId(obj[GENERICS_DATA][x])] += 1;
}
@ -375,26 +381,23 @@ window.initSearch = function(rawSearchIndex) {
if (allFound) {
return true;
}
} else {
return false;
}
return false;
}
return true;
}
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
var tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
} else {
return 0;
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
var tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
}
}
}
// Names didn't match so let's check if one of the generic types could.
if (literalSearch) {
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
} else if (literalSearch) {
if ((!val.generics || val.generics.length === 0) &&
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
return obj[GENERICS_DATA].some(
function(name) {
return name === val.name;
@ -1167,7 +1170,48 @@ window.initSearch = function(rawSearchIndex) {
return ret;
}
var queries = query.raw.split(",");
// Split search query by ",", while respecting angle bracket nesting.
// Since "<" is an alias for the Ord family of traits, it also uses
// lookahead to distinguish "<"-as-less-than from "<"-as-angle-bracket.
//
// tokenizeQuery("A<B, C>, D") == ["A<B, C>", "D"]
// tokenizeQuery("A<B, C, D") == ["A<B", "C", "D"]
function tokenizeQuery(raw) {
var i, matched;
var l = raw.length;
var depth = 0;
var nextAngle = /(<|>)/g;
var ret = [];
var start = 0;
for (i = 0; i < l; ++i) {
switch (raw[i]) {
case "<":
nextAngle.lastIndex = i + 1;
matched = nextAngle.exec(raw);
if (matched && matched[1] === '>') {
depth += 1;
}
break;
case ">":
if (depth > 0) {
depth -= 1;
}
break;
case ",":
if (depth === 0) {
ret.push(raw.substring(start, i));
start = i + 1;
}
break;
}
}
if (start !== i) {
ret.push(raw.substring(start, i));
}
return ret;
}
var queries = tokenizeQuery(query.raw);
var results = {
"in_args": [],
"returned": [],

View file

@ -0,0 +1,7 @@
const QUERY = '<';
const EXPECTED = {
'others': [
{ 'name': 'Ord' },
],
};

View file

@ -0,0 +1,23 @@
const QUERY = [
'Result<SomeTrait>',
'OtherThingxxxxxxxx',
];
const EXPECTED = [
{
'in_args': [
{ 'path': 'generics_trait', 'name': 'beta' },
],
'returned': [
{ 'path': 'generics_trait', 'name': 'bet' },
],
},
{
'in_args': [
{ 'path': 'generics_trait', 'name': 'alpha' },
],
'returned': [
{ 'path': 'generics_trait', 'name': 'alef' },
],
},
];

View file

@ -0,0 +1,8 @@
pub trait SomeTrait {}
pub trait OtherThingxxxxxxxx {}
pub fn alef<T: OtherThingxxxxxxxx>() -> Result<T, ()> { loop {} }
pub fn bet<T: SomeTrait>() -> Result<T, ()> { loop {} }
pub fn alpha<T: OtherThingxxxxxxxx>(_param: Result<T, ()>) { loop {} }
pub fn beta<T: SomeTrait>(_param: Result<T, ()>) { loop {} }

View file

@ -0,0 +1,44 @@
// exact-check
const QUERY = [
'"R<P>"',
'"P"',
'P',
'"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
];
const EXPECTED = [
{
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
],
},
{
'others': [
{ 'path': 'generics', 'name': 'P' },
],
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
],
},
{
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
],
},
{
'in_args': [
{ 'path': 'generics', 'name': 'extracreditlabhomework' },
],
'returned': [],
},
];

View file

@ -0,0 +1,21 @@
pub struct P;
pub struct Q;
pub struct R<T>(T);
// returns test
pub fn alef() -> R<P> { loop {} }
pub fn bet() -> R<Q> { loop {} }
// in_args test
pub fn alpha(_x: R<P>) { loop {} }
pub fn beta(_x: R<Q>) { loop {} }
// test case with multiple appearances of the same type
pub struct ExtraCreditStructMulti<T, U> { t: T, u: U }
pub struct ExtraCreditInnerMulti {}
pub fn extracreditlabhomework(
_param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
) { loop {} }
pub fn redherringmatchforextracredit(
_param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>
) { loop {} }

View file

@ -0,0 +1,22 @@
#![feature(const_trait_impl)]
#![allow(incomplete_features)]
#![feature(staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait MyTrait {
#[stable(feature = "rust1", since = "1.0.0")]
fn func();
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Unstable;
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "staged", issue = "none")]
impl const MyTrait for Unstable {
fn func() {
}
}

View file

@ -1,18 +0,0 @@
// aux-build: cross-crate.rs
extern crate cross_crate;
use cross_crate::*;
fn non_const_context() {
NonConst.func();
Const.func();
}
const fn const_context() {
NonConst.func();
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
Const.func();
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
}
fn main() {}

View file

@ -1,5 +1,5 @@
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/cross-crate-feature-enabled.rs:15:5
--> $DIR/cross-crate.rs:16:5
|
LL | NonConst.func();
| ^^^^^^^^^^^^^^^

View file

@ -1,4 +1,5 @@
#![feature(const_trait_impl)]
// revisions: stock gated
#![cfg_attr(gated, feature(const_trait_impl))]
#![allow(incomplete_features)]
// aux-build: cross-crate.rs
@ -15,6 +16,7 @@ const fn const_context() {
NonConst.func();
//~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
Const.func();
//[stock]~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
}
fn main() {}

View file

@ -1,11 +1,11 @@
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/cross-crate-feature-disabled.rs:12:5
--> $DIR/cross-crate.rs:16:5
|
LL | NonConst.func();
| ^^^^^^^^^^^^^^^
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/cross-crate-feature-disabled.rs:14:5
--> $DIR/cross-crate.rs:18:5
|
LL | Const.func();
| ^^^^^^^^^^^^

View file

@ -0,0 +1,39 @@
// revisions: stock staged
#![cfg_attr(staged, feature(staged))]
#![feature(const_trait_impl)]
#![allow(incomplete_features)]
#![feature(staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]
// aux-build: staged-api.rs
extern crate staged_api;
use staged_api::*;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stable;
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(staged, rustc_const_stable(feature = "rust1", since = "1.0.0"))]
// ^ should trigger error with or without the attribute
impl const MyTrait for Stable {
fn func() { //~ ERROR trait methods cannot be stable const fn
}
}
fn non_const_context() {
Unstable::func();
Stable::func();
}
#[unstable(feature = "none", issue = "none")]
const fn const_context() {
Unstable::func();
//[stock]~^ ERROR `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
Stable::func();
}
fn main() {}

View file

@ -0,0 +1,10 @@
error: trait methods cannot be stable const fn
--> $DIR/staged-api.rs:22:5
|
LL | / fn func() {
LL | |
LL | | }
| |_____^
error: aborting due to previous error

View file

@ -0,0 +1,18 @@
error: trait methods cannot be stable const fn
--> $DIR/staged-api.rs:22:5
|
LL | / fn func() {
LL | |
LL | | }
| |_____^
error: `<staged_api::Unstable as staged_api::MyTrait>::func` is not yet stable as a const fn
--> $DIR/staged-api.rs:34:5
|
LL | Unstable::func();
| ^^^^^^^^^^^^^^^^
|
= help: add `#![feature(staged)]` to the crate attributes to enable
error: aborting due to 2 previous errors

View file

@ -0,0 +1,19 @@
// Check that appropriate errors are reported if an intrinsic is defined
// with the wrong number of generic lifetime/type/const parameters, and
// that no ICE occurs in these cases.
#![feature(platform_intrinsics)]
#![crate_type="lib"]
extern "platform-intrinsic" {
fn simd_saturating_add<'a, T: 'a>(x: T, y: T);
//~^ ERROR: intrinsic has wrong number of lifetime parameters
fn simd_add<'a, T>(x: T, y: T) -> T;
fn simd_sub<T, U>(x: T, y: U);
//~^ ERROR: intrinsic has wrong number of type parameters
fn simd_mul<T, const N: usize>(x: T, y: T);
//~^ ERROR: intrinsic has wrong number of const parameters
}

View file

@ -0,0 +1,21 @@
error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0
--> $DIR/issue-85855.rs:9:27
|
LL | fn simd_saturating_add<'a, T: 'a>(x: T, y: T);
| ^^^^^^^^^^^ expected 0 lifetime parameters
error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1
--> $DIR/issue-85855.rs:14:16
|
LL | fn simd_sub<T, U>(x: T, y: U);
| ^^^^^^ expected 1 type parameter
error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0
--> $DIR/issue-85855.rs:17:16
|
LL | fn simd_mul<T, const N: usize>(x: T, y: T);
| ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0094`.

View file

@ -4,7 +4,7 @@ allow-unauthenticated = [
"D-*",
"requires-nightly",
"regression-*",
"perf-regression",
"perf-*",
# I-* without I-nominated
"I-*", "!I-nominated",
"AsyncAwait-OnDeck",