Auto merge of #58098 - oli-obk:maybe_allow_internal_unstable, r=petrochenkov
Require a list of features in `#[allow_internal_unstable]` The blanket-permission slip is not great and will likely give us trouble some point down the road.
This commit is contained in:
commit
c84e797642
41 changed files with 622 additions and 512 deletions
|
@ -34,7 +34,8 @@
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(not(stage0), allow_internal_unstable(box_syntax))]
|
||||||
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
macro_rules! vec {
|
macro_rules! vec {
|
||||||
($elem:expr; $n:expr) => (
|
($elem:expr; $n:expr) => (
|
||||||
$crate::vec::from_elem($elem, $n)
|
$crate::vec::from_elem($elem, $n)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/// Entry point of thread panic, for details, see std::macros
|
/// Entry point of thread panic, for details, see std::macros
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(not(stage0), allow_internal_unstable(core_panic, __rust_unstable_column))]
|
||||||
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
#[stable(feature = "core", since = "1.6.0")]
|
#[stable(feature = "core", since = "1.6.0")]
|
||||||
macro_rules! panic {
|
macro_rules! panic {
|
||||||
() => (
|
() => (
|
||||||
|
@ -409,7 +410,8 @@ macro_rules! write {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(format_args_nl))]
|
||||||
macro_rules! writeln {
|
macro_rules! writeln {
|
||||||
($dst:expr) => (
|
($dst:expr) => (
|
||||||
write!($dst, "\n")
|
write!($dst, "\n")
|
||||||
|
|
|
@ -44,6 +44,7 @@ use crate::middle::cstore::CrateStore;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use rustc_data_structures::thin_vec::ThinVec;
|
use rustc_data_structures::thin_vec::ThinVec;
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
use crate::session::config::nightly_options;
|
use crate::session::config::nightly_options;
|
||||||
use crate::util::common::FN_OUTPUT_NAME;
|
use crate::util::common::FN_OUTPUT_NAME;
|
||||||
|
@ -681,13 +682,20 @@ impl<'a> LoweringContext<'a> {
|
||||||
Ident::with_empty_ctxt(Symbol::gensym(s))
|
Ident::with_empty_ctxt(Symbol::gensym(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) -> Span {
|
/// Reuses the span but adds information like the kind of the desugaring and features that are
|
||||||
|
/// allowed inside this span.
|
||||||
|
fn mark_span_with_reason(
|
||||||
|
&self,
|
||||||
|
reason: CompilerDesugaringKind,
|
||||||
|
span: Span,
|
||||||
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
|
) -> Span {
|
||||||
let mark = Mark::fresh(Mark::root());
|
let mark = Mark::fresh(Mark::root());
|
||||||
mark.set_expn_info(source_map::ExpnInfo {
|
mark.set_expn_info(source_map::ExpnInfo {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
def_site: Some(span),
|
def_site: Some(span),
|
||||||
format: source_map::CompilerDesugaring(reason),
|
format: source_map::CompilerDesugaring(reason),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: source_map::hygiene::default_edition(),
|
edition: source_map::hygiene::default_edition(),
|
||||||
|
@ -964,7 +972,13 @@ impl<'a> LoweringContext<'a> {
|
||||||
attrs: ThinVec::new(),
|
attrs: ThinVec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span);
|
let unstable_span = self.mark_span_with_reason(
|
||||||
|
CompilerDesugaringKind::Async,
|
||||||
|
span,
|
||||||
|
Some(vec![
|
||||||
|
Symbol::intern("gen_future"),
|
||||||
|
].into()),
|
||||||
|
);
|
||||||
let gen_future = self.expr_std_path(
|
let gen_future = self.expr_std_path(
|
||||||
unstable_span, &["future", "from_generator"], None, ThinVec::new());
|
unstable_span, &["future", "from_generator"], None, ThinVec::new());
|
||||||
hir::ExprKind::Call(P(gen_future), hir_vec![generator])
|
hir::ExprKind::Call(P(gen_future), hir_vec![generator])
|
||||||
|
@ -1360,9 +1374,10 @@ impl<'a> LoweringContext<'a> {
|
||||||
// desugaring that explicitly states that we don't want to track that.
|
// desugaring that explicitly states that we don't want to track that.
|
||||||
// Not tracking it makes lints in rustc and clippy very fragile as
|
// Not tracking it makes lints in rustc and clippy very fragile as
|
||||||
// frequently opened issues show.
|
// frequently opened issues show.
|
||||||
let exist_ty_span = self.allow_internal_unstable(
|
let exist_ty_span = self.mark_span_with_reason(
|
||||||
CompilerDesugaringKind::ExistentialReturnType,
|
CompilerDesugaringKind::ExistentialReturnType,
|
||||||
span,
|
span,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let exist_ty_def_index = self
|
let exist_ty_def_index = self
|
||||||
|
@ -3927,8 +3942,13 @@ impl<'a> LoweringContext<'a> {
|
||||||
}),
|
}),
|
||||||
ExprKind::TryBlock(ref body) => {
|
ExprKind::TryBlock(ref body) => {
|
||||||
self.with_catch_scope(body.id, |this| {
|
self.with_catch_scope(body.id, |this| {
|
||||||
let unstable_span =
|
let unstable_span = this.mark_span_with_reason(
|
||||||
this.allow_internal_unstable(CompilerDesugaringKind::TryBlock, body.span);
|
CompilerDesugaringKind::TryBlock,
|
||||||
|
body.span,
|
||||||
|
Some(vec![
|
||||||
|
Symbol::intern("try_trait"),
|
||||||
|
].into()),
|
||||||
|
);
|
||||||
let mut block = this.lower_block(body, true).into_inner();
|
let mut block = this.lower_block(body, true).into_inner();
|
||||||
let tail = block.expr.take().map_or_else(
|
let tail = block.expr.take().map_or_else(
|
||||||
|| {
|
|| {
|
||||||
|
@ -4360,9 +4380,10 @@ impl<'a> LoweringContext<'a> {
|
||||||
// expand <head>
|
// expand <head>
|
||||||
let head = self.lower_expr(head);
|
let head = self.lower_expr(head);
|
||||||
let head_sp = head.span;
|
let head_sp = head.span;
|
||||||
let desugared_span = self.allow_internal_unstable(
|
let desugared_span = self.mark_span_with_reason(
|
||||||
CompilerDesugaringKind::ForLoop,
|
CompilerDesugaringKind::ForLoop,
|
||||||
head_sp,
|
head_sp,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let iter = self.str_to_ident("iter");
|
let iter = self.str_to_ident("iter");
|
||||||
|
@ -4525,8 +4546,13 @@ impl<'a> LoweringContext<'a> {
|
||||||
// return Try::from_error(From::from(err)),
|
// return Try::from_error(From::from(err)),
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let unstable_span =
|
let unstable_span = self.mark_span_with_reason(
|
||||||
self.allow_internal_unstable(CompilerDesugaringKind::QuestionMark, e.span);
|
CompilerDesugaringKind::QuestionMark,
|
||||||
|
e.span,
|
||||||
|
Some(vec![
|
||||||
|
Symbol::intern("try_trait")
|
||||||
|
].into()),
|
||||||
|
);
|
||||||
|
|
||||||
// `Try::into_result(<expr>)`
|
// `Try::into_result(<expr>)`
|
||||||
let discr = {
|
let discr = {
|
||||||
|
|
|
@ -561,11 +561,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
|
/// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
|
||||||
/// `id`.
|
/// `id`.
|
||||||
pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> EvalResult {
|
pub fn eval_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) -> EvalResult {
|
||||||
if span.allows_unstable() {
|
|
||||||
debug!("stability: skipping span={:?} since it is internal", span);
|
|
||||||
return EvalResult::Allow;
|
|
||||||
}
|
|
||||||
|
|
||||||
let lint_deprecated = |def_id: DefId,
|
let lint_deprecated = |def_id: DefId,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
note: Option<Symbol>,
|
note: Option<Symbol>,
|
||||||
|
@ -694,6 +689,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
match stability {
|
match stability {
|
||||||
Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => {
|
Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => {
|
||||||
|
if span.allows_unstable(&feature.as_str()) {
|
||||||
|
debug!("stability: skipping span={:?} since it is internal", span);
|
||||||
|
return EvalResult::Allow;
|
||||||
|
}
|
||||||
if self.stability().active_features.contains(&feature) {
|
if self.stability().active_features.contains(&feature) {
|
||||||
return EvalResult::Allow;
|
return EvalResult::Allow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,9 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
|
||||||
call_site: item.span, // use the call site of the static
|
call_site: item.span, // use the call site of the static
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern(name)),
|
format: MacroAttribute(Symbol::intern(name)),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/// A simple static assertion macro. The first argument should be a unique
|
/// A simple static assertion macro. The first argument should be a unique
|
||||||
/// ALL_CAPS identifier that describes the condition.
|
/// ALL_CAPS identifier that describes the condition.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(type_ascription))]
|
||||||
macro_rules! static_assert {
|
macro_rules! static_assert {
|
||||||
($name:ident: $test:expr) => {
|
($name:ident: $test:expr) => {
|
||||||
// Use the bool to access an array such that if the bool is false, the access
|
// Use the bool to access an array such that if the bool is false, the access
|
||||||
|
|
|
@ -570,7 +570,7 @@ impl<'a> CrateLoader<'a> {
|
||||||
ProcMacro::Bang { name, client } => {
|
ProcMacro::Bang { name, client } => {
|
||||||
(name, SyntaxExtension::ProcMacro {
|
(name, SyntaxExtension::ProcMacro {
|
||||||
expander: Box::new(BangProcMacro { client }),
|
expander: Box::new(BangProcMacro { client }),
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
edition: root.edition,
|
edition: root.edition,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,7 +425,9 @@ impl cstore::CStore {
|
||||||
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
||||||
let ext = SyntaxExtension::ProcMacro {
|
let ext = SyntaxExtension::ProcMacro {
|
||||||
expander: Box::new(BangProcMacro { client }),
|
expander: Box::new(BangProcMacro { client }),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("proc_macro_def_site"),
|
||||||
|
].into()),
|
||||||
edition: data.root.edition,
|
edition: data.root.edition,
|
||||||
};
|
};
|
||||||
return LoadedMacro::ProcMacro(Lrc::new(ext));
|
return LoadedMacro::ProcMacro(Lrc::new(ext));
|
||||||
|
|
|
@ -909,7 +909,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
// Check `#[unstable]` const fns or `#[rustc_const_unstable]`
|
// Check `#[unstable]` const fns or `#[rustc_const_unstable]`
|
||||||
// functions without the feature gate active in this crate in
|
// functions without the feature gate active in this crate in
|
||||||
// order to report a better error message than the one below.
|
// order to report a better error message than the one below.
|
||||||
if self.span.allows_unstable() {
|
if self.span.allows_unstable(&feature.as_str()) {
|
||||||
// `allow_internal_unstable` can make such calls stable.
|
// `allow_internal_unstable` can make such calls stable.
|
||||||
is_const_fn = true;
|
is_const_fn = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -110,8 +110,8 @@ impl<'a> Registry<'a> {
|
||||||
edition,
|
edition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IdentTT(ext, _, allow_internal_unstable) => {
|
IdentTT { expander, span: _, allow_internal_unstable } => {
|
||||||
IdentTT(ext, Some(self.krate_span), allow_internal_unstable)
|
IdentTT { expander, span: Some(self.krate_span), allow_internal_unstable }
|
||||||
}
|
}
|
||||||
_ => extension,
|
_ => extension,
|
||||||
}));
|
}));
|
||||||
|
@ -126,7 +126,7 @@ impl<'a> Registry<'a> {
|
||||||
self.register_syntax_extension(Symbol::intern(name), NormalTT {
|
self.register_syntax_extension(Symbol::intern(name), NormalTT {
|
||||||
expander: Box::new(expander),
|
expander: Box::new(expander),
|
||||||
def_info: None,
|
def_info: None,
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
unstable_feature: None,
|
unstable_feature: None,
|
||||||
|
|
|
@ -53,7 +53,8 @@
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(__rust_unstable_column, libstd_sys_internals))]
|
||||||
macro_rules! panic {
|
macro_rules! panic {
|
||||||
() => ({
|
() => ({
|
||||||
panic!("explicit panic")
|
panic!("explicit panic")
|
||||||
|
@ -111,7 +112,8 @@ macro_rules! panic {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
|
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
@ -143,7 +145,8 @@ macro_rules! print {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
() => (print!("\n"));
|
() => (print!("\n"));
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
|
@ -174,7 +177,8 @@ macro_rules! println {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "eprint", since = "1.19.0")]
|
#[stable(feature = "eprint", since = "1.19.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(print_internals))]
|
||||||
macro_rules! eprint {
|
macro_rules! eprint {
|
||||||
($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
|
($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
@ -202,7 +206,8 @@ macro_rules! eprint {
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "eprint", since = "1.19.0")]
|
#[stable(feature = "eprint", since = "1.19.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(print_internals, format_args_nl))]
|
||||||
macro_rules! eprintln {
|
macro_rules! eprintln {
|
||||||
() => (eprint!("\n"));
|
() => (eprint!("\n"));
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
|
@ -325,7 +330,8 @@ macro_rules! dbg {
|
||||||
/// A macro to await on an async call.
|
/// A macro to await on an async call.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[unstable(feature = "await_macro", issue = "50547")]
|
#[unstable(feature = "await_macro", issue = "50547")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(gen_future, generators))]
|
||||||
#[allow_internal_unsafe]
|
#[allow_internal_unsafe]
|
||||||
macro_rules! await {
|
macro_rules! await {
|
||||||
($e:expr) => { {
|
($e:expr) => { {
|
||||||
|
|
|
@ -279,6 +279,9 @@ use self::select::StartResult;
|
||||||
use self::select::StartResult::*;
|
use self::select::StartResult::*;
|
||||||
use self::blocking::SignalToken;
|
use self::blocking::SignalToken;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||||
|
mod select_tests;
|
||||||
|
|
||||||
mod blocking;
|
mod blocking;
|
||||||
mod oneshot;
|
mod oneshot;
|
||||||
mod select;
|
mod select;
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl Select {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper method for skipping the preflight checks during testing
|
/// Helper method for skipping the preflight checks during testing
|
||||||
fn wait2(&self, do_preflight_checks: bool) -> usize {
|
pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize {
|
||||||
// Note that this is currently an inefficient implementation. We in
|
// Note that this is currently an inefficient implementation. We in
|
||||||
// theory have knowledge about all receivers in the set ahead of time,
|
// theory have knowledge about all receivers in the set ahead of time,
|
||||||
// so this method shouldn't really have to iterate over all of them yet
|
// so this method shouldn't really have to iterate over all of them yet
|
||||||
|
@ -352,417 +352,3 @@ impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
|
||||||
f.debug_struct("Handle").finish()
|
f.debug_struct("Handle").finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
#[cfg(all(test, not(target_os = "emscripten")))]
|
|
||||||
mod tests {
|
|
||||||
use thread;
|
|
||||||
use sync::mpsc::*;
|
|
||||||
|
|
||||||
// Don't use the libstd version so we can pull in the right Select structure
|
|
||||||
// (std::comm points at the wrong one)
|
|
||||||
macro_rules! select {
|
|
||||||
(
|
|
||||||
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
|
|
||||||
) => ({
|
|
||||||
let sel = Select::new();
|
|
||||||
$( let mut $rx = sel.handle(&$rx); )+
|
|
||||||
unsafe {
|
|
||||||
$( $rx.add(); )+
|
|
||||||
}
|
|
||||||
let ret = sel.wait();
|
|
||||||
$( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
|
|
||||||
{ unreachable!() }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke() {
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (tx2, rx2) = channel::<i32>();
|
|
||||||
tx1.send(1).unwrap();
|
|
||||||
select! {
|
|
||||||
foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
|
|
||||||
_bar = rx2.recv() => { panic!() }
|
|
||||||
}
|
|
||||||
tx2.send(2).unwrap();
|
|
||||||
select! {
|
|
||||||
_foo = rx1.recv() => { panic!() },
|
|
||||||
bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
|
|
||||||
}
|
|
||||||
drop(tx1);
|
|
||||||
select! {
|
|
||||||
foo = rx1.recv() => { assert!(foo.is_err()); },
|
|
||||||
_bar = rx2.recv() => { panic!() }
|
|
||||||
}
|
|
||||||
drop(tx2);
|
|
||||||
select! {
|
|
||||||
bar = rx2.recv() => { assert!(bar.is_err()); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke2() {
|
|
||||||
let (_tx1, rx1) = channel::<i32>();
|
|
||||||
let (_tx2, rx2) = channel::<i32>();
|
|
||||||
let (_tx3, rx3) = channel::<i32>();
|
|
||||||
let (_tx4, rx4) = channel::<i32>();
|
|
||||||
let (tx5, rx5) = channel::<i32>();
|
|
||||||
tx5.send(4).unwrap();
|
|
||||||
select! {
|
|
||||||
_foo = rx1.recv() => { panic!("1") },
|
|
||||||
_foo = rx2.recv() => { panic!("2") },
|
|
||||||
_foo = rx3.recv() => { panic!("3") },
|
|
||||||
_foo = rx4.recv() => { panic!("4") },
|
|
||||||
foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn closed() {
|
|
||||||
let (_tx1, rx1) = channel::<i32>();
|
|
||||||
let (tx2, rx2) = channel::<i32>();
|
|
||||||
drop(tx2);
|
|
||||||
|
|
||||||
select! {
|
|
||||||
_a1 = rx1.recv() => { panic!() },
|
|
||||||
a2 = rx2.recv() => { assert!(a2.is_err()); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblocks() {
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (_tx2, rx2) = channel::<i32>();
|
|
||||||
let (tx3, rx3) = channel::<i32>();
|
|
||||||
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
for _ in 0..20 { thread::yield_now(); }
|
|
||||||
tx1.send(1).unwrap();
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
for _ in 0..20 { thread::yield_now(); }
|
|
||||||
});
|
|
||||||
|
|
||||||
select! {
|
|
||||||
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
|
||||||
_b = rx2.recv() => { panic!() }
|
|
||||||
}
|
|
||||||
tx3.send(1).unwrap();
|
|
||||||
select! {
|
|
||||||
a = rx1.recv() => { assert!(a.is_err()) },
|
|
||||||
_b = rx2.recv() => { panic!() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn both_ready() {
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (tx2, rx2) = channel::<i32>();
|
|
||||||
let (tx3, rx3) = channel::<()>();
|
|
||||||
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
for _ in 0..20 { thread::yield_now(); }
|
|
||||||
tx1.send(1).unwrap();
|
|
||||||
tx2.send(2).unwrap();
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
select! {
|
|
||||||
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
|
||||||
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
|
|
||||||
}
|
|
||||||
select! {
|
|
||||||
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
|
||||||
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
|
|
||||||
}
|
|
||||||
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
|
|
||||||
assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn stress() {
|
|
||||||
const AMT: i32 = 10000;
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (tx2, rx2) = channel::<i32>();
|
|
||||||
let (tx3, rx3) = channel::<()>();
|
|
||||||
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
for i in 0..AMT {
|
|
||||||
if i % 2 == 0 {
|
|
||||||
tx1.send(i).unwrap();
|
|
||||||
} else {
|
|
||||||
tx2.send(i).unwrap();
|
|
||||||
}
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
for i in 0..AMT {
|
|
||||||
select! {
|
|
||||||
i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
|
|
||||||
i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
|
|
||||||
}
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
#[test]
|
|
||||||
fn cloning() {
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (_tx2, rx2) = channel::<i32>();
|
|
||||||
let (tx3, rx3) = channel::<()>();
|
|
||||||
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
tx1.clone();
|
|
||||||
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
|
|
||||||
tx1.send(2).unwrap();
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
select! {
|
|
||||||
_i1 = rx1.recv() => {},
|
|
||||||
_i2 = rx2.recv() => panic!()
|
|
||||||
}
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
#[test]
|
|
||||||
fn cloning2() {
|
|
||||||
let (tx1, rx1) = channel::<i32>();
|
|
||||||
let (_tx2, rx2) = channel::<i32>();
|
|
||||||
let (tx3, rx3) = channel::<()>();
|
|
||||||
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
tx1.clone();
|
|
||||||
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
|
|
||||||
tx1.send(2).unwrap();
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
select! {
|
|
||||||
_i1 = rx1.recv() => {},
|
|
||||||
_i2 = rx2.recv() => panic!()
|
|
||||||
}
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn cloning3() {
|
|
||||||
let (tx1, rx1) = channel::<()>();
|
|
||||||
let (tx2, rx2) = channel::<()>();
|
|
||||||
let (tx3, rx3) = channel::<()>();
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h1 = s.handle(&rx1);
|
|
||||||
let mut h2 = s.handle(&rx2);
|
|
||||||
unsafe { h2.add(); }
|
|
||||||
unsafe { h1.add(); }
|
|
||||||
assert_eq!(s.wait(), h2.id);
|
|
||||||
tx3.send(()).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
for _ in 0..1000 { thread::yield_now(); }
|
|
||||||
drop(tx1.clone());
|
|
||||||
tx2.send(()).unwrap();
|
|
||||||
rx3.recv().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight1() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
select! {
|
|
||||||
_n = rx.recv() => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight2() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
select! {
|
|
||||||
_n = rx.recv() => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight3() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
drop(tx.clone());
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
select! {
|
|
||||||
_n = rx.recv() => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight4() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight5() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight6() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
drop(tx.clone());
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight7() {
|
|
||||||
let (tx, rx) = channel::<()>();
|
|
||||||
drop(tx);
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight8() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
drop(tx);
|
|
||||||
rx.recv().unwrap();
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn preflight9() {
|
|
||||||
let (tx, rx) = channel();
|
|
||||||
drop(tx.clone());
|
|
||||||
tx.send(()).unwrap();
|
|
||||||
drop(tx);
|
|
||||||
rx.recv().unwrap();
|
|
||||||
let s = Select::new();
|
|
||||||
let mut h = s.handle(&rx);
|
|
||||||
unsafe { h.add(); }
|
|
||||||
assert_eq!(s.wait2(false), h.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn oneshot_data_waiting() {
|
|
||||||
let (tx1, rx1) = channel();
|
|
||||||
let (tx2, rx2) = channel();
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
select! {
|
|
||||||
_n = rx1.recv() => {}
|
|
||||||
}
|
|
||||||
tx2.send(()).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
for _ in 0..100 { thread::yield_now() }
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
rx2.recv().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn stream_data_waiting() {
|
|
||||||
let (tx1, rx1) = channel();
|
|
||||||
let (tx2, rx2) = channel();
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
rx1.recv().unwrap();
|
|
||||||
rx1.recv().unwrap();
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
select! {
|
|
||||||
_n = rx1.recv() => {}
|
|
||||||
}
|
|
||||||
tx2.send(()).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
for _ in 0..100 { thread::yield_now() }
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
rx2.recv().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn shared_data_waiting() {
|
|
||||||
let (tx1, rx1) = channel();
|
|
||||||
let (tx2, rx2) = channel();
|
|
||||||
drop(tx1.clone());
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
rx1.recv().unwrap();
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
select! {
|
|
||||||
_n = rx1.recv() => {}
|
|
||||||
}
|
|
||||||
tx2.send(()).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
for _ in 0..100 { thread::yield_now() }
|
|
||||||
tx1.send(()).unwrap();
|
|
||||||
rx2.recv().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sync1() {
|
|
||||||
let (tx, rx) = sync_channel::<i32>(1);
|
|
||||||
tx.send(1).unwrap();
|
|
||||||
select! {
|
|
||||||
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sync2() {
|
|
||||||
let (tx, rx) = sync_channel::<i32>(0);
|
|
||||||
let _t = thread::spawn(move|| {
|
|
||||||
for _ in 0..100 { thread::yield_now() }
|
|
||||||
tx.send(1).unwrap();
|
|
||||||
});
|
|
||||||
select! {
|
|
||||||
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sync3() {
|
|
||||||
let (tx1, rx1) = sync_channel::<i32>(0);
|
|
||||||
let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
|
|
||||||
let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
|
|
||||||
let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
|
|
||||||
select! {
|
|
||||||
n = rx1.recv() => {
|
|
||||||
let n = n.unwrap();
|
|
||||||
assert_eq!(n, 1);
|
|
||||||
assert_eq!(rx2.recv().unwrap(), 2);
|
|
||||||
},
|
|
||||||
n = rx2.recv() => {
|
|
||||||
let n = n.unwrap();
|
|
||||||
assert_eq!(n, 2);
|
|
||||||
assert_eq!(rx1.recv().unwrap(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
413
src/libstd/sync/mpsc/select_tests.rs
Normal file
413
src/libstd/sync/mpsc/select_tests.rs
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238
|
||||||
|
|
||||||
|
use thread;
|
||||||
|
use sync::mpsc::*;
|
||||||
|
|
||||||
|
// Don't use the libstd version so we can pull in the right Select structure
|
||||||
|
// (std::comm points at the wrong one)
|
||||||
|
macro_rules! select {
|
||||||
|
(
|
||||||
|
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
|
||||||
|
) => ({
|
||||||
|
let sel = Select::new();
|
||||||
|
$( let mut $rx = sel.handle(&$rx); )+
|
||||||
|
unsafe {
|
||||||
|
$( $rx.add(); )+
|
||||||
|
}
|
||||||
|
let ret = sel.wait();
|
||||||
|
$( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+
|
||||||
|
{ unreachable!() }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() {
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (tx2, rx2) = channel::<i32>();
|
||||||
|
tx1.send(1).unwrap();
|
||||||
|
select! {
|
||||||
|
foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); },
|
||||||
|
_bar = rx2.recv() => { panic!() }
|
||||||
|
}
|
||||||
|
tx2.send(2).unwrap();
|
||||||
|
select! {
|
||||||
|
_foo = rx1.recv() => { panic!() },
|
||||||
|
bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) }
|
||||||
|
}
|
||||||
|
drop(tx1);
|
||||||
|
select! {
|
||||||
|
foo = rx1.recv() => { assert!(foo.is_err()); },
|
||||||
|
_bar = rx2.recv() => { panic!() }
|
||||||
|
}
|
||||||
|
drop(tx2);
|
||||||
|
select! {
|
||||||
|
bar = rx2.recv() => { assert!(bar.is_err()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke2() {
|
||||||
|
let (_tx1, rx1) = channel::<i32>();
|
||||||
|
let (_tx2, rx2) = channel::<i32>();
|
||||||
|
let (_tx3, rx3) = channel::<i32>();
|
||||||
|
let (_tx4, rx4) = channel::<i32>();
|
||||||
|
let (tx5, rx5) = channel::<i32>();
|
||||||
|
tx5.send(4).unwrap();
|
||||||
|
select! {
|
||||||
|
_foo = rx1.recv() => { panic!("1") },
|
||||||
|
_foo = rx2.recv() => { panic!("2") },
|
||||||
|
_foo = rx3.recv() => { panic!("3") },
|
||||||
|
_foo = rx4.recv() => { panic!("4") },
|
||||||
|
foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closed() {
|
||||||
|
let (_tx1, rx1) = channel::<i32>();
|
||||||
|
let (tx2, rx2) = channel::<i32>();
|
||||||
|
drop(tx2);
|
||||||
|
|
||||||
|
select! {
|
||||||
|
_a1 = rx1.recv() => { panic!() },
|
||||||
|
a2 = rx2.recv() => { assert!(a2.is_err()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblocks() {
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (_tx2, rx2) = channel::<i32>();
|
||||||
|
let (tx3, rx3) = channel::<i32>();
|
||||||
|
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
for _ in 0..20 { thread::yield_now(); }
|
||||||
|
tx1.send(1).unwrap();
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
for _ in 0..20 { thread::yield_now(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
select! {
|
||||||
|
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
||||||
|
_b = rx2.recv() => { panic!() }
|
||||||
|
}
|
||||||
|
tx3.send(1).unwrap();
|
||||||
|
select! {
|
||||||
|
a = rx1.recv() => { assert!(a.is_err()) },
|
||||||
|
_b = rx2.recv() => { panic!() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn both_ready() {
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (tx2, rx2) = channel::<i32>();
|
||||||
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
for _ in 0..20 { thread::yield_now(); }
|
||||||
|
tx1.send(1).unwrap();
|
||||||
|
tx2.send(2).unwrap();
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
select! {
|
||||||
|
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
||||||
|
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
|
||||||
|
}
|
||||||
|
select! {
|
||||||
|
a = rx1.recv() => { assert_eq!(a.unwrap(), 1); },
|
||||||
|
a = rx2.recv() => { assert_eq!(a.unwrap(), 2); }
|
||||||
|
}
|
||||||
|
assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty));
|
||||||
|
assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty));
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stress() {
|
||||||
|
const AMT: i32 = 10000;
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (tx2, rx2) = channel::<i32>();
|
||||||
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
for i in 0..AMT {
|
||||||
|
if i % 2 == 0 {
|
||||||
|
tx1.send(i).unwrap();
|
||||||
|
} else {
|
||||||
|
tx2.send(i).unwrap();
|
||||||
|
}
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for i in 0..AMT {
|
||||||
|
select! {
|
||||||
|
i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); },
|
||||||
|
i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); }
|
||||||
|
}
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
#[test]
|
||||||
|
fn cloning() {
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (_tx2, rx2) = channel::<i32>();
|
||||||
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
tx1.clone();
|
||||||
|
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
|
||||||
|
tx1.send(2).unwrap();
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
select! {
|
||||||
|
_i1 = rx1.recv() => {},
|
||||||
|
_i2 = rx2.recv() => panic!()
|
||||||
|
}
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_must_use)]
|
||||||
|
#[test]
|
||||||
|
fn cloning2() {
|
||||||
|
let (tx1, rx1) = channel::<i32>();
|
||||||
|
let (_tx2, rx2) = channel::<i32>();
|
||||||
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
tx1.clone();
|
||||||
|
assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty));
|
||||||
|
tx1.send(2).unwrap();
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
select! {
|
||||||
|
_i1 = rx1.recv() => {},
|
||||||
|
_i2 = rx2.recv() => panic!()
|
||||||
|
}
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cloning3() {
|
||||||
|
let (tx1, rx1) = channel::<()>();
|
||||||
|
let (tx2, rx2) = channel::<()>();
|
||||||
|
let (tx3, rx3) = channel::<()>();
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h1 = s.handle(&rx1);
|
||||||
|
let mut h2 = s.handle(&rx2);
|
||||||
|
unsafe { h2.add(); }
|
||||||
|
unsafe { h1.add(); }
|
||||||
|
assert_eq!(s.wait(), h2.id());
|
||||||
|
tx3.send(()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..1000 { thread::yield_now(); }
|
||||||
|
drop(tx1.clone());
|
||||||
|
tx2.send(()).unwrap();
|
||||||
|
rx3.recv().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight1() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
select! {
|
||||||
|
_n = rx.recv() => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight2() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
select! {
|
||||||
|
_n = rx.recv() => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight3() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
drop(tx.clone());
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
select! {
|
||||||
|
_n = rx.recv() => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight4() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight5() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight6() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
drop(tx.clone());
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight7() {
|
||||||
|
let (tx, rx) = channel::<()>();
|
||||||
|
drop(tx);
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight8() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
drop(tx);
|
||||||
|
rx.recv().unwrap();
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn preflight9() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
drop(tx.clone());
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
drop(tx);
|
||||||
|
rx.recv().unwrap();
|
||||||
|
let s = Select::new();
|
||||||
|
let mut h = s.handle(&rx);
|
||||||
|
unsafe { h.add(); }
|
||||||
|
assert_eq!(s.wait2(false), h.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn oneshot_data_waiting() {
|
||||||
|
let (tx1, rx1) = channel();
|
||||||
|
let (tx2, rx2) = channel();
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
select! {
|
||||||
|
_n = rx1.recv() => {}
|
||||||
|
}
|
||||||
|
tx2.send(()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..100 { thread::yield_now() }
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
rx2.recv().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stream_data_waiting() {
|
||||||
|
let (tx1, rx1) = channel();
|
||||||
|
let (tx2, rx2) = channel();
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
rx1.recv().unwrap();
|
||||||
|
rx1.recv().unwrap();
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
select! {
|
||||||
|
_n = rx1.recv() => {}
|
||||||
|
}
|
||||||
|
tx2.send(()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..100 { thread::yield_now() }
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
rx2.recv().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shared_data_waiting() {
|
||||||
|
let (tx1, rx1) = channel();
|
||||||
|
let (tx2, rx2) = channel();
|
||||||
|
drop(tx1.clone());
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
rx1.recv().unwrap();
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
select! {
|
||||||
|
_n = rx1.recv() => {}
|
||||||
|
}
|
||||||
|
tx2.send(()).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
for _ in 0..100 { thread::yield_now() }
|
||||||
|
tx1.send(()).unwrap();
|
||||||
|
rx2.recv().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync1() {
|
||||||
|
let (tx, rx) = sync_channel::<i32>(1);
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
select! {
|
||||||
|
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync2() {
|
||||||
|
let (tx, rx) = sync_channel::<i32>(0);
|
||||||
|
let _t = thread::spawn(move|| {
|
||||||
|
for _ in 0..100 { thread::yield_now() }
|
||||||
|
tx.send(1).unwrap();
|
||||||
|
});
|
||||||
|
select! {
|
||||||
|
n = rx.recv() => { assert_eq!(n.unwrap(), 1); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync3() {
|
||||||
|
let (tx1, rx1) = sync_channel::<i32>(0);
|
||||||
|
let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();
|
||||||
|
let _t = thread::spawn(move|| { tx1.send(1).unwrap(); });
|
||||||
|
let _t = thread::spawn(move|| { tx2.send(2).unwrap(); });
|
||||||
|
select! {
|
||||||
|
n = rx1.recv() => {
|
||||||
|
let n = n.unwrap();
|
||||||
|
assert_eq!(n, 1);
|
||||||
|
assert_eq!(rx2.recv().unwrap(), 2);
|
||||||
|
},
|
||||||
|
n = rx2.recv() => {
|
||||||
|
let n = n.unwrap();
|
||||||
|
assert_eq!(n, 2);
|
||||||
|
assert_eq!(rx1.recv().unwrap(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,7 +126,8 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
|
||||||
/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html
|
/// [`std::thread::LocalKey`]: ../std/thread/struct.LocalKey.html
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(thread_local_internals))]
|
||||||
macro_rules! thread_local {
|
macro_rules! thread_local {
|
||||||
// empty (base case for the recursion)
|
// empty (base case for the recursion)
|
||||||
() => {};
|
() => {};
|
||||||
|
@ -148,7 +149,10 @@ macro_rules! thread_local {
|
||||||
reason = "should not be necessary",
|
reason = "should not be necessary",
|
||||||
issue = "0")]
|
issue = "0")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[allow_internal_unstable]
|
#[cfg_attr(stage0, allow_internal_unstable)]
|
||||||
|
#[cfg_attr(not(stage0), allow_internal_unstable(
|
||||||
|
thread_local_internals, cfg_target_thread_local, thread_local,
|
||||||
|
))]
|
||||||
#[allow_internal_unsafe]
|
#[allow_internal_unsafe]
|
||||||
macro_rules! __thread_local_inner {
|
macro_rules! __thread_local_inner {
|
||||||
(@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
|
(@key $(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
|
||||||
|
|
|
@ -621,7 +621,8 @@ pub enum SyntaxExtension {
|
||||||
/// A function-like procedural macro. TokenStream -> TokenStream.
|
/// A function-like procedural macro. TokenStream -> TokenStream.
|
||||||
ProcMacro {
|
ProcMacro {
|
||||||
expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
|
expander: Box<dyn ProcMacro + sync::Sync + sync::Send>,
|
||||||
allow_internal_unstable: bool,
|
/// Whitelist of unstable features that are treated as stable inside this macro
|
||||||
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -638,8 +639,10 @@ pub enum SyntaxExtension {
|
||||||
expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
|
expander: Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
|
||||||
def_info: Option<(ast::NodeId, Span)>,
|
def_info: Option<(ast::NodeId, Span)>,
|
||||||
/// Whether the contents of the macro can
|
/// Whether the contents of the macro can
|
||||||
/// directly use `#[unstable]` things (true == yes).
|
/// directly use `#[unstable]` things.
|
||||||
allow_internal_unstable: bool,
|
///
|
||||||
|
/// Only allows things that require a feature gate in the given whitelist
|
||||||
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
/// Whether the contents of the macro can use `unsafe`
|
/// Whether the contents of the macro can use `unsafe`
|
||||||
/// without triggering the `unsafe_code` lint.
|
/// without triggering the `unsafe_code` lint.
|
||||||
allow_internal_unsafe: bool,
|
allow_internal_unsafe: bool,
|
||||||
|
@ -654,8 +657,11 @@ pub enum SyntaxExtension {
|
||||||
|
|
||||||
/// A function-like syntax extension that has an extra ident before
|
/// A function-like syntax extension that has an extra ident before
|
||||||
/// the block.
|
/// the block.
|
||||||
///
|
IdentTT {
|
||||||
IdentTT(Box<dyn IdentMacroExpander + sync::Sync + sync::Send>, Option<Span>, bool),
|
expander: Box<dyn IdentMacroExpander + sync::Sync + sync::Send>,
|
||||||
|
span: Option<Span>,
|
||||||
|
allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
|
},
|
||||||
|
|
||||||
/// An attribute-like procedural macro. TokenStream -> TokenStream.
|
/// An attribute-like procedural macro. TokenStream -> TokenStream.
|
||||||
/// The input is the annotated item.
|
/// The input is the annotated item.
|
||||||
|
@ -682,7 +688,7 @@ impl SyntaxExtension {
|
||||||
match *self {
|
match *self {
|
||||||
SyntaxExtension::DeclMacro { .. } |
|
SyntaxExtension::DeclMacro { .. } |
|
||||||
SyntaxExtension::NormalTT { .. } |
|
SyntaxExtension::NormalTT { .. } |
|
||||||
SyntaxExtension::IdentTT(..) |
|
SyntaxExtension::IdentTT { .. } |
|
||||||
SyntaxExtension::ProcMacro { .. } =>
|
SyntaxExtension::ProcMacro { .. } =>
|
||||||
MacroKind::Bang,
|
MacroKind::Bang,
|
||||||
SyntaxExtension::NonMacroAttr { .. } |
|
SyntaxExtension::NonMacroAttr { .. } |
|
||||||
|
@ -716,7 +722,7 @@ impl SyntaxExtension {
|
||||||
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
|
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
|
||||||
// Unstable legacy stuff
|
// Unstable legacy stuff
|
||||||
SyntaxExtension::NonMacroAttr { .. } |
|
SyntaxExtension::NonMacroAttr { .. } |
|
||||||
SyntaxExtension::IdentTT(..) |
|
SyntaxExtension::IdentTT { .. } |
|
||||||
SyntaxExtension::MultiDecorator(..) |
|
SyntaxExtension::MultiDecorator(..) |
|
||||||
SyntaxExtension::MultiModifier(..) |
|
SyntaxExtension::MultiModifier(..) |
|
||||||
SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
|
SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
|
||||||
|
|
|
@ -58,7 +58,10 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
|
||||||
call_site: span,
|
call_site: span,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
|
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
Symbol::intern("structural_match"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -558,7 +558,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
call_site: attr.span,
|
call_site: attr.span,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
|
format: MacroAttribute(Symbol::intern(&attr.path.to_string())),
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: ext.edition(),
|
edition: ext.edition(),
|
||||||
|
@ -725,7 +725,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
// don't stability-check macros in the same crate
|
// don't stability-check macros in the same crate
|
||||||
// (the only time this is null is for syntax extensions registered as macros)
|
// (the only time this is null is for syntax extensions registered as macros)
|
||||||
if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
|
if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span))
|
||||||
&& !span.allows_unstable() && this.cx.ecfg.features.map_or(true, |feats| {
|
&& !span.allows_unstable(&feature.as_str())
|
||||||
|
&& this.cx.ecfg.features.map_or(true, |feats| {
|
||||||
// macro features will count as lib features
|
// macro features will count as lib features
|
||||||
!feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
|
!feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
|
||||||
}) {
|
}) {
|
||||||
|
@ -757,7 +758,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
let opt_expanded = match *ext {
|
let opt_expanded = match *ext {
|
||||||
DeclMacro { ref expander, def_info, edition, .. } => {
|
DeclMacro { ref expander, def_info, edition, .. } => {
|
||||||
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
|
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
|
||||||
false, false, false, None,
|
None, false, false, None,
|
||||||
edition) {
|
edition) {
|
||||||
dummy_span
|
dummy_span
|
||||||
} else {
|
} else {
|
||||||
|
@ -768,14 +769,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
NormalTT {
|
NormalTT {
|
||||||
ref expander,
|
ref expander,
|
||||||
def_info,
|
def_info,
|
||||||
allow_internal_unstable,
|
ref allow_internal_unstable,
|
||||||
allow_internal_unsafe,
|
allow_internal_unsafe,
|
||||||
local_inner_macros,
|
local_inner_macros,
|
||||||
unstable_feature,
|
unstable_feature,
|
||||||
edition,
|
edition,
|
||||||
} => {
|
} => {
|
||||||
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
|
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
|
||||||
allow_internal_unstable,
|
allow_internal_unstable.clone(),
|
||||||
allow_internal_unsafe,
|
allow_internal_unsafe,
|
||||||
local_inner_macros,
|
local_inner_macros,
|
||||||
unstable_feature,
|
unstable_feature,
|
||||||
|
@ -791,7 +792,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
|
IdentTT { ref expander, span: tt_span, ref allow_internal_unstable } => {
|
||||||
if ident.name == keywords::Invalid.name() {
|
if ident.name == keywords::Invalid.name() {
|
||||||
self.cx.span_err(path.span,
|
self.cx.span_err(path.span,
|
||||||
&format!("macro {}! expects an ident argument", path));
|
&format!("macro {}! expects an ident argument", path));
|
||||||
|
@ -802,7 +803,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
def_site: tt_span,
|
def_site: tt_span,
|
||||||
format: macro_bang_format(path),
|
format: macro_bang_format(path),
|
||||||
allow_internal_unstable,
|
allow_internal_unstable: allow_internal_unstable.clone(),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
@ -827,7 +828,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
kind.dummy(span)
|
kind.dummy(span)
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxExtension::ProcMacro { ref expander, allow_internal_unstable, edition } => {
|
SyntaxExtension::ProcMacro { ref expander, ref allow_internal_unstable, edition } => {
|
||||||
if ident.name != keywords::Invalid.name() {
|
if ident.name != keywords::Invalid.name() {
|
||||||
let msg =
|
let msg =
|
||||||
format!("macro {}! expects no ident argument, given '{}'", path, ident);
|
format!("macro {}! expects no ident argument, given '{}'", path, ident);
|
||||||
|
@ -843,7 +844,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: macro_bang_format(path),
|
format: macro_bang_format(path),
|
||||||
// FIXME probably want to follow macro_rules macros here.
|
// FIXME probably want to follow macro_rules macros here.
|
||||||
allow_internal_unstable,
|
allow_internal_unstable: allow_internal_unstable.clone(),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition,
|
edition,
|
||||||
|
@ -918,7 +919,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
call_site: span,
|
call_site: span,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(pretty_name),
|
format: MacroAttribute(pretty_name),
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: ext.edition(),
|
edition: ext.edition(),
|
||||||
|
@ -937,7 +938,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||||
Some(invoc.fragment_kind.expect_from_annotatables(items))
|
Some(invoc.fragment_kind.expect_from_annotatables(items))
|
||||||
}
|
}
|
||||||
BuiltinDerive(func) => {
|
BuiltinDerive(func) => {
|
||||||
expn_info.allow_internal_unstable = true;
|
expn_info.allow_internal_unstable = Some(vec![
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
Symbol::intern("derive_clone_copy"),
|
||||||
|
Symbol::intern("derive_eq"),
|
||||||
|
Symbol::intern("libstd_sys_internals"), // RustcDeserialize and RustcSerialize
|
||||||
|
].into());
|
||||||
invoc.expansion_data.mark.set_expn_info(expn_info);
|
invoc.expansion_data.mark.set_expn_info(expn_info);
|
||||||
let span = span.with_ctxt(self.cx.backtrace());
|
let span = span.with_ctxt(self.cx.backtrace());
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr
|
||||||
/* __rust_unstable_column!(): expands to the current column number */
|
/* __rust_unstable_column!(): expands to the current column number */
|
||||||
pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
|
pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
|
||||||
-> Box<dyn base::MacResult+'static> {
|
-> Box<dyn base::MacResult+'static> {
|
||||||
if sp.allows_unstable() {
|
if sp.allows_unstable("__rust_unstable_column") {
|
||||||
expand_column(cx, sp, tts)
|
expand_column(cx, sp, tts)
|
||||||
} else {
|
} else {
|
||||||
cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
|
cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
|
||||||
|
|
|
@ -376,7 +376,24 @@ pub fn compile(
|
||||||
});
|
});
|
||||||
|
|
||||||
if body.legacy {
|
if body.legacy {
|
||||||
let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
|
let allow_internal_unstable = attr::find_by_name(&def.attrs, "allow_internal_unstable")
|
||||||
|
.map(|attr| attr
|
||||||
|
.meta_item_list()
|
||||||
|
.map(|list| list.iter()
|
||||||
|
.map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug(
|
||||||
|
it.span, "allow internal unstable expects feature names",
|
||||||
|
)))
|
||||||
|
.collect::<Vec<Symbol>>().into()
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
sess.span_diagnostic.span_warn(
|
||||||
|
attr.span, "allow_internal_unstable expects list of feature names. In the \
|
||||||
|
future this will become a hard error. Please use `allow_internal_unstable(\
|
||||||
|
foo, bar)` to only allow the `foo` and `bar` features",
|
||||||
|
);
|
||||||
|
vec![Symbol::intern("allow_internal_unstable_backcompat_hack")].into()
|
||||||
|
})
|
||||||
|
);
|
||||||
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
|
let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe");
|
||||||
let mut local_inner_macros = false;
|
let mut local_inner_macros = false;
|
||||||
if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
|
if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") {
|
||||||
|
|
|
@ -1091,7 +1091,8 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
|
||||||
stable",
|
stable",
|
||||||
cfg_fn!(profiler_runtime))),
|
cfg_fn!(profiler_runtime))),
|
||||||
|
|
||||||
("allow_internal_unstable", Normal, template!(Word), Gated(Stability::Unstable,
|
("allow_internal_unstable", Normal, template!(Word, List: "feat1, feat2, ..."),
|
||||||
|
Gated(Stability::Unstable,
|
||||||
"allow_internal_unstable",
|
"allow_internal_unstable",
|
||||||
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
|
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
|
||||||
cfg_fn!(allow_internal_unstable))),
|
cfg_fn!(allow_internal_unstable))),
|
||||||
|
@ -1199,7 +1200,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
|
||||||
("proc_macro", Normal, template!(Word), Ungated),
|
("proc_macro", Normal, template!(Word), Ungated),
|
||||||
|
|
||||||
("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable,
|
("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable,
|
||||||
"rustc_proc_macro_decls",
|
"rustc_attrs",
|
||||||
"used internally by rustc",
|
"used internally by rustc",
|
||||||
cfg_fn!(rustc_attrs))),
|
cfg_fn!(rustc_attrs))),
|
||||||
|
|
||||||
|
@ -1284,7 +1285,7 @@ impl GatedCfg {
|
||||||
|
|
||||||
pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
|
pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
|
||||||
let (cfg, feature, has_feature) = GATED_CFGS[self.index];
|
let (cfg, feature, has_feature) = GATED_CFGS[self.index];
|
||||||
if !has_feature(features) && !self.span.allows_unstable() {
|
if !has_feature(features) && !self.span.allows_unstable(feature) {
|
||||||
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
|
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
|
||||||
emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
|
emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
|
||||||
}
|
}
|
||||||
|
@ -1303,7 +1304,7 @@ macro_rules! gate_feature_fn {
|
||||||
name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
|
name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level);
|
||||||
let has_feature: bool = has_feature(&$cx.features);
|
let has_feature: bool = has_feature(&$cx.features);
|
||||||
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
|
||||||
if !has_feature && !span.allows_unstable() {
|
if !has_feature && !span.allows_unstable($name) {
|
||||||
leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
|
leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -1328,7 +1329,11 @@ impl<'a> Context<'a> {
|
||||||
for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
|
for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
|
||||||
if name == n {
|
if name == n {
|
||||||
if let Gated(_, name, desc, ref has_feature) = *gateage {
|
if let Gated(_, name, desc, ref has_feature) = *gateage {
|
||||||
gate_feature_fn!(self, has_feature, attr.span, name, desc, GateStrength::Hard);
|
if !attr.span.allows_unstable(name) {
|
||||||
|
gate_feature_fn!(
|
||||||
|
self, has_feature, attr.span, name, desc, GateStrength::Hard
|
||||||
|
);
|
||||||
|
}
|
||||||
} else if name == "doc" {
|
} else if name == "doc" {
|
||||||
if let Some(content) = attr.meta_item_list() {
|
if let Some(content) = attr.meta_item_list() {
|
||||||
if content.iter().any(|c| c.check_name("include")) {
|
if content.iter().any(|c| c.check_name("include")) {
|
||||||
|
@ -1493,13 +1498,13 @@ struct PostExpansionVisitor<'a> {
|
||||||
macro_rules! gate_feature_post {
|
macro_rules! gate_feature_post {
|
||||||
($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
|
($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
|
||||||
let (cx, span) = ($cx, $span);
|
let (cx, span) = ($cx, $span);
|
||||||
if !span.allows_unstable() {
|
if !span.allows_unstable(stringify!($feature)) {
|
||||||
gate_feature!(cx.context, $feature, span, $explain)
|
gate_feature!(cx.context, $feature, span, $explain)
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
|
($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{
|
||||||
let (cx, span) = ($cx, $span);
|
let (cx, span) = ($cx, $span);
|
||||||
if !span.allows_unstable() {
|
if !span.allows_unstable(stringify!($feature)) {
|
||||||
gate_feature!(cx.context, $feature, span, $explain, $level)
|
gate_feature!(cx.context, $feature, span, $explain, $level)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -1610,10 +1615,8 @@ impl<'a> PostExpansionVisitor<'a> {
|
||||||
|
|
||||||
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||||
if !attr.span.allows_unstable() {
|
|
||||||
// check for gated attributes
|
// check for gated attributes
|
||||||
self.context.check_attribute(attr, false);
|
self.context.check_attribute(attr, false);
|
||||||
}
|
|
||||||
|
|
||||||
if attr.check_name("doc") {
|
if attr.check_name("doc") {
|
||||||
if let Some(content) = attr.meta_item_list() {
|
if let Some(content) = attr.meta_item_list() {
|
||||||
|
|
|
@ -20,7 +20,9 @@ fn ignored_span(sp: Span) -> Span {
|
||||||
call_site: DUMMY_SP,
|
call_site: DUMMY_SP,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern("std_inject")),
|
format: MacroAttribute(Symbol::intern("std_inject")),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("prelude_import"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -285,7 +285,11 @@ fn generate_test_harness(sess: &ParseSess,
|
||||||
call_site: DUMMY_SP,
|
call_site: DUMMY_SP,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern("test_case")),
|
format: MacroAttribute(Symbol::intern("test_case")),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("main"),
|
||||||
|
Symbol::intern("test"),
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -136,11 +136,16 @@ fn call_intrinsic(cx: &ExtCtxt<'_>,
|
||||||
intrinsic: &str,
|
intrinsic: &str,
|
||||||
args: Vec<P<ast::Expr>>)
|
args: Vec<P<ast::Expr>>)
|
||||||
-> P<ast::Expr> {
|
-> P<ast::Expr> {
|
||||||
if cx.current_expansion.mark.expn_info().unwrap().allow_internal_unstable {
|
let intrinsic_allowed_via_allow_internal_unstable = cx
|
||||||
|
.current_expansion.mark.expn_info().unwrap()
|
||||||
|
.allow_internal_unstable.map_or(false, |features| features.iter().any(|&s|
|
||||||
|
s == "core_intrinsics"
|
||||||
|
));
|
||||||
|
if intrinsic_allowed_via_allow_internal_unstable {
|
||||||
span = span.with_ctxt(cx.backtrace());
|
span = span.with_ctxt(cx.backtrace());
|
||||||
} else { // Avoid instability errors with user defined curstom derives, cc #36316
|
} else { // Avoid instability errors with user defined curstom derives, cc #36316
|
||||||
let mut info = cx.current_expansion.mark.expn_info().unwrap();
|
let mut info = cx.current_expansion.mark.expn_info().unwrap();
|
||||||
info.allow_internal_unstable = true;
|
info.allow_internal_unstable = Some(vec![Symbol::intern("core_intrinsics")].into());
|
||||||
let mark = Mark::fresh(Mark::root());
|
let mark = Mark::fresh(Mark::root());
|
||||||
mark.set_expn_info(info);
|
mark.set_expn_info(info);
|
||||||
span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
|
span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
|
||||||
|
|
|
@ -711,7 +711,7 @@ pub fn expand_format_args_nl<'cx>(
|
||||||
//if !ecx.ecfg.enable_allow_internal_unstable() {
|
//if !ecx.ecfg.enable_allow_internal_unstable() {
|
||||||
|
|
||||||
// For some reason, the only one that actually works for `println` is the first check
|
// For some reason, the only one that actually works for `println` is the first check
|
||||||
if !sp.allows_unstable() // the enclosing span is marked as `#[allow_insternal_unsable]`
|
if !sp.allows_unstable("format_args_nl") // the span is marked as `#[allow_insternal_unsable]`
|
||||||
&& !ecx.ecfg.enable_allow_internal_unstable() // NOTE: when is this enabled?
|
&& !ecx.ecfg.enable_allow_internal_unstable() // NOTE: when is this enabled?
|
||||||
&& !ecx.ecfg.enable_format_args_nl() // enabled using `#[feature(format_args_nl]`
|
&& !ecx.ecfg.enable_format_args_nl() // enabled using `#[feature(format_args_nl]`
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
|
||||||
NormalTT {
|
NormalTT {
|
||||||
expander: Box::new($f as MacroExpanderFn),
|
expander: Box::new($f as MacroExpanderFn),
|
||||||
def_info: None,
|
def_info: None,
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
unstable_feature: None,
|
unstable_feature: None,
|
||||||
|
@ -104,7 +104,9 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
|
||||||
NormalTT {
|
NormalTT {
|
||||||
expander: Box::new(format::expand_format_args),
|
expander: Box::new(format::expand_format_args),
|
||||||
def_info: None,
|
def_info: None,
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("fmt_internals"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
unstable_feature: None,
|
unstable_feature: None,
|
||||||
|
@ -114,7 +116,9 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
|
||||||
NormalTT {
|
NormalTT {
|
||||||
expander: Box::new(format::expand_format_args_nl),
|
expander: Box::new(format::expand_format_args_nl),
|
||||||
def_info: None,
|
def_info: None,
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("fmt_internals"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
unstable_feature: None,
|
unstable_feature: None,
|
||||||
|
|
|
@ -333,7 +333,10 @@ fn mk_decls(
|
||||||
call_site: DUMMY_SP,
|
call_site: DUMMY_SP,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern("proc_macro")),
|
format: MacroAttribute(Symbol::intern("proc_macro")),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
Symbol::intern("proc_macro_internals"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -66,7 +66,10 @@ pub fn expand_test_or_bench(
|
||||||
call_site: DUMMY_SP,
|
call_site: DUMMY_SP,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern("test")),
|
format: MacroAttribute(Symbol::intern("test")),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
Symbol::intern("test"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -41,7 +41,10 @@ pub fn expand(
|
||||||
call_site: DUMMY_SP,
|
call_site: DUMMY_SP,
|
||||||
def_site: None,
|
def_site: None,
|
||||||
format: MacroAttribute(Symbol::intern("test_case")),
|
format: MacroAttribute(Symbol::intern("test_case")),
|
||||||
allow_internal_unstable: true,
|
allow_internal_unstable: Some(vec![
|
||||||
|
Symbol::intern("test"),
|
||||||
|
Symbol::intern("rustc_attrs"),
|
||||||
|
].into()),
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
edition: hygiene::default_edition(),
|
edition: hygiene::default_edition(),
|
||||||
|
|
|
@ -12,6 +12,7 @@ use crate::symbol::{keywords, Symbol};
|
||||||
|
|
||||||
use serialize::{Encodable, Decodable, Encoder, Decoder};
|
use serialize::{Encodable, Decodable, Encoder, Decoder};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
use rustc_data_structures::sync::Lrc;
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
|
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
|
||||||
|
@ -550,10 +551,10 @@ pub struct ExpnInfo {
|
||||||
pub def_site: Option<Span>,
|
pub def_site: Option<Span>,
|
||||||
/// The format with which the macro was invoked.
|
/// The format with which the macro was invoked.
|
||||||
pub format: ExpnFormat,
|
pub format: ExpnFormat,
|
||||||
/// Whether the macro is allowed to use #[unstable]/feature-gated
|
/// List of #[unstable]/feature-gated features that the macro is allowed to use
|
||||||
/// features internally without forcing the whole crate to opt-in
|
/// internally without forcing the whole crate to opt-in
|
||||||
/// to them.
|
/// to them.
|
||||||
pub allow_internal_unstable: bool,
|
pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
|
||||||
/// Whether the macro is allowed to use `unsafe` internally
|
/// Whether the macro is allowed to use `unsafe` internally
|
||||||
/// even if the user crate has `#![forbid(unsafe_code)]`.
|
/// even if the user crate has `#![forbid(unsafe_code)]`.
|
||||||
pub allow_internal_unsafe: bool,
|
pub allow_internal_unsafe: bool,
|
||||||
|
|
|
@ -386,9 +386,13 @@ impl Span {
|
||||||
/// Check if a span is "internal" to a macro in which `#[unstable]`
|
/// Check if a span is "internal" to a macro in which `#[unstable]`
|
||||||
/// items can be used (that is, a macro marked with
|
/// items can be used (that is, a macro marked with
|
||||||
/// `#[allow_internal_unstable]`).
|
/// `#[allow_internal_unstable]`).
|
||||||
pub fn allows_unstable(&self) -> bool {
|
pub fn allows_unstable(&self, feature: &str) -> bool {
|
||||||
match self.ctxt().outer().expn_info() {
|
match self.ctxt().outer().expn_info() {
|
||||||
Some(info) => info.allow_internal_unstable,
|
Some(info) => info
|
||||||
|
.allow_internal_unstable
|
||||||
|
.map_or(false, |features| features.iter().any(|&f|
|
||||||
|
f == feature || f == "allow_internal_unstable_backcompat_hack"
|
||||||
|
)),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
NormalTT {
|
NormalTT {
|
||||||
expander: Box::new(Expander { args: args, }),
|
expander: Box::new(Expander { args: args, }),
|
||||||
def_info: None,
|
def_info: None,
|
||||||
allow_internal_unstable: false,
|
allow_internal_unstable: None,
|
||||||
allow_internal_unsafe: false,
|
allow_internal_unsafe: false,
|
||||||
local_inner_macros: false,
|
local_inner_macros: false,
|
||||||
unstable_feature: None,
|
unstable_feature: None,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
macro_rules! bar {
|
macro_rules! bar {
|
||||||
() => {
|
() => {
|
||||||
// more layers don't help:
|
// more layers don't help:
|
||||||
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
#[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
macro_rules! baz {
|
macro_rules! baz {
|
||||||
() => {}
|
() => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
||||||
--> $DIR/feature-gate-allow-internal-unstable-nested-macro.rs:8:9
|
--> $DIR/feature-gate-allow-internal-unstable-nested-macro.rs:8:9
|
||||||
|
|
|
|
||||||
LL | #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
...
|
...
|
||||||
LL | bar!();
|
LL | bar!();
|
||||||
| ------- in this macro invocation
|
| ------- in this macro invocation
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// checks that this attribute is caught on non-macro items.
|
// checks that this attribute is caught on non-macro items.
|
||||||
// this needs a different test since this is done after expansion
|
// this needs a different test since this is done after expansion
|
||||||
|
|
||||||
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
#[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
||||||
--> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1
|
--> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1
|
||||||
|
|
|
|
||||||
LL | #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: add #![feature(allow_internal_unstable)] to the crate attributes to enable
|
= help: add #![feature(allow_internal_unstable)] to the crate attributes to enable
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![allow(unused_macros)]
|
#![allow(unused_macros)]
|
||||||
|
|
||||||
#[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
#[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
() => {}
|
() => {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
|
||||||
--> $DIR/feature-gate-allow-internal-unstable.rs:3:1
|
--> $DIR/feature-gate-allow-internal-unstable.rs:3:1
|
||||||
|
|
|
|
||||||
LL | #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps
|
LL | #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: add #![feature(allow_internal_unstable)] to the crate attributes to enable
|
= help: add #![feature(allow_internal_unstable)] to the crate attributes to enable
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,14 @@ pub struct Bar {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "stable", since = "1.0.0")]
|
#[stable(feature = "stable", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable(function)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! call_unstable_allow {
|
macro_rules! call_unstable_allow {
|
||||||
() => { $crate::unstable() }
|
() => { $crate::unstable() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "stable", since = "1.0.0")]
|
#[stable(feature = "stable", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable(struct_field)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! construct_unstable_allow {
|
macro_rules! construct_unstable_allow {
|
||||||
($e: expr) => {
|
($e: expr) => {
|
||||||
|
@ -39,21 +39,21 @@ macro_rules! construct_unstable_allow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "stable", since = "1.0.0")]
|
#[stable(feature = "stable", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable(method)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! call_method_allow {
|
macro_rules! call_method_allow {
|
||||||
($e: expr) => { $e.method() }
|
($e: expr) => { $e.method() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "stable", since = "1.0.0")]
|
#[stable(feature = "stable", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable(struct_field, struct2_field)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! access_field_allow {
|
macro_rules! access_field_allow {
|
||||||
($e: expr) => { $e.x }
|
($e: expr) => { $e.x }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "stable", since = "1.0.0")]
|
#[stable(feature = "stable", since = "1.0.0")]
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable()]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! pass_through_allow {
|
macro_rules! pass_through_allow {
|
||||||
($e: expr) => { $e }
|
($e: expr) => { $e }
|
||||||
|
|
|
@ -13,7 +13,7 @@ macro_rules! foo {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow_internal_unstable]
|
#[allow_internal_unstable(function)]
|
||||||
macro_rules! bar {
|
macro_rules! bar {
|
||||||
($e: expr) => {{
|
($e: expr) => {{
|
||||||
foo!($e,
|
foo!($e,
|
||||||
|
|
|
@ -58,6 +58,7 @@ const EXCEPTION_PATHS: &[&str] = &[
|
||||||
"src/libstd/sys_common/net.rs",
|
"src/libstd/sys_common/net.rs",
|
||||||
"src/libterm", // Not sure how to make this crate portable, but test crate needs it.
|
"src/libterm", // Not sure how to make this crate portable, but test crate needs it.
|
||||||
"src/libtest", // Probably should defer to unstable `std::sys` APIs.
|
"src/libtest", // Probably should defer to unstable `std::sys` APIs.
|
||||||
|
"src/libstd/sync/mpsc", // some tests are only run on non-emscripten
|
||||||
|
|
||||||
// std testing crates, okay for now at least
|
// std testing crates, okay for now at least
|
||||||
"src/libcore/tests",
|
"src/libcore/tests",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue