1
Fork 0

Auto merge of #138595 - jhpratt:rollup-09pvfzu, r=jhpratt

Rollup of 9 pull requests

Successful merges:

 - #136355 (Add `*_value` methods to proc_macro lib)
 - #137621 (Add std support to cygwin target)
 - #137793 (Stablize anonymous pipe)
 - #138341 (std: Mention clone-on-write mutation in Arc<T>)
 - #138517 (Improve upvar analysis for deref of child capture)
 - #138584 (Update Rust Foundation links in Readme)
 - #138586 (Document `#![register_tool]`)
 - #138590 (Flatten and simplify some control flow 🫓)
 - #138592 (update change entry for #137147)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-03-17 10:43:38 +00:00
commit 9c67cecd12
88 changed files with 1025 additions and 341 deletions

View file

@ -2082,6 +2082,13 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "literal-escaper"
version = "0.0.0"
dependencies = [
"rustc-std-workspace-std 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lld-wrapper"
version = "0.1.0"
@ -3148,6 +3155,12 @@ version = "1.0.1"
name = "rustc-std-workspace-std"
version = "1.0.1"
[[package]]
name = "rustc-std-workspace-std"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aba676a20abe46e5b0f1b0deae474aaaf31407e6c71147159890574599da04ef"
[[package]]
name = "rustc_abi"
version = "0.0.0"
@ -3186,6 +3199,7 @@ name = "rustc_ast"
version = "0.0.0"
dependencies = [
"bitflags",
"literal-escaper",
"memchr",
"rustc_ast_ir",
"rustc_data_structures",
@ -3895,6 +3909,7 @@ name = "rustc_lexer"
version = "0.0.0"
dependencies = [
"expect-test",
"literal-escaper",
"memchr",
"unicode-properties",
"unicode-xid",
@ -4157,6 +4172,7 @@ name = "rustc_parse"
version = "0.0.0"
dependencies = [
"bitflags",
"literal-escaper",
"rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures",
@ -4179,6 +4195,7 @@ dependencies = [
name = "rustc_parse_format"
version = "0.0.0"
dependencies = [
"literal-escaper",
"rustc_index",
"rustc_lexer",
]

View file

@ -67,11 +67,11 @@ See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT), and
trademarks and logos (the "Rust Trademarks").
If you want to use these names or brands, please read the
[media guide][media-guide].
[Rust language trademark policy][trademark-policy].
Third-party logos may be subject to third-party copyrights and trademarks. See
[Licenses][policies-licenses] for details.
[rust-foundation]: https://foundation.rust-lang.org/
[media-guide]: https://foundation.rust-lang.org/policies/logo-policy-and-media-guide/
[rust-foundation]: https://rustfoundation.org/
[trademark-policy]: https://rustfoundation.org/policy/rust-trademark-policy/
[policies-licenses]: https://www.rust-lang.org/policies/licenses

View file

@ -6,6 +6,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
literal-escaper = { path = "../../library/literal-escaper" }
memchr = "2.7.4"
rustc_ast_ir = { path = "../rustc_ast_ir" }
rustc_data_structures = { path = "../rustc_data_structures" }

View file

@ -2,7 +2,7 @@
use std::{ascii, fmt, str};
use rustc_lexer::unescape::{
use literal_escaper::{
MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode,
};
use rustc_span::{Span, Symbol, kw, sym};

View file

@ -2479,19 +2479,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
let body = self.body;
for local in body.mut_vars_and_args_iter().filter(|local| !self.used_mut.contains(local)) {
let local_decl = &body.local_decls[local];
let lint_root = match &body.source_scopes[local_decl.source_info.scope].local_data {
ClearCrossCrate::Set(data) => data.lint_root,
_ => continue,
let ClearCrossCrate::Set(SourceScopeLocalData { lint_root, .. }) =
body.source_scopes[local_decl.source_info.scope].local_data
else {
continue;
};
// Skip over locals that begin with an underscore or have no name
match self.local_names[local] {
Some(name) => {
if name.as_str().starts_with('_') {
continue;
}
}
None => continue,
if self.local_names[local].is_none_or(|name| name.as_str().starts_with('_')) {
continue;
}
let span = local_decl.source_info.span;

View file

@ -153,10 +153,9 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
}
// If `#[link_section]` is missing, then nothing to verify
let attrs = tcx.codegen_fn_attrs(id);
if attrs.link_section.is_none() {
let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
return;
}
};
// For the wasm32 target statics with `#[link_section]` other than `.init_array`
// are placed into custom sections of the final output file, but this isn't like
@ -182,11 +181,8 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
// continue to work, but would no longer be necessary.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
&& alloc.inner().provenance().ptrs().len() != 0
&& attrs
.link_section
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
.unwrap()
&& !alloc.inner().provenance().ptrs().is_empty()
&& !link_section.as_str().starts_with(".init_array")
{
let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \

View file

@ -1532,30 +1532,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.may_coerce(blk_ty, *elem_ty)
&& blk.stmts.is_empty()
&& blk.rules == hir::BlockCheckMode::DefaultBlock
&& let source_map = self.tcx.sess.source_map()
&& let Ok(snippet) = source_map.span_to_snippet(blk.span)
&& snippet.starts_with('{')
&& snippet.ends_with('}')
{
let source_map = self.tcx.sess.source_map();
if let Ok(snippet) = source_map.span_to_snippet(blk.span) {
if snippet.starts_with('{') && snippet.ends_with('}') {
diag.multipart_suggestion_verbose(
"to create an array, use square brackets instead of curly braces",
vec![
(
blk.span
.shrink_to_lo()
.with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)),
"[".to_string(),
),
(
blk.span
.shrink_to_hi()
.with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)),
"]".to_string(),
),
],
Applicability::MachineApplicable,
);
}
}
diag.multipart_suggestion_verbose(
"to create an array, use square brackets instead of curly braces",
vec![
(
blk.span
.shrink_to_lo()
.with_hi(rustc_span::BytePos(blk.span.lo().0 + 1)),
"[".to_string(),
),
(
blk.span
.shrink_to_hi()
.with_lo(rustc_span::BytePos(blk.span.hi().0 - 1)),
"]".to_string(),
),
],
Applicability::MachineApplicable,
);
}
}
}

View file

@ -1862,8 +1862,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
///
/// (1.) Are we borrowing data owned by the parent closure? We can determine if
/// that is the case by checking if the parent capture is by move, EXCEPT if we
/// apply a deref projection, which means we're reborrowing a reference that we
/// captured by move.
/// apply a deref projection of an immutable reference, reborrows of immutable
/// references which aren't restricted to the LUB of the lifetimes of the deref
/// chain. This is why `&'short mut &'long T` can be reborrowed as `&'long T`.
///
/// ```rust
/// let x = &1i32; // Let's call this lifetime `'1`.
@ -1902,10 +1903,22 @@ fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
) -> bool {
// (1.)
(!parent_capture.is_by_ref()
&& !matches!(
child_capture.place.projections.get(parent_capture.place.projections.len()),
Some(Projection { kind: ProjectionKind::Deref, .. })
))
// This is just inlined `place.deref_tys()` but truncated to just
// the child projections. Namely, look for a `&T` deref, since we
// can always extend `&'short mut &'long T` to `&'long T`.
&& !child_capture
.place
.projections
.iter()
.enumerate()
.skip(parent_capture.place.projections.len())
.any(|(idx, proj)| {
matches!(proj.kind, ProjectionKind::Deref)
&& matches!(
child_capture.place.ty_before_projection(idx).kind(),
ty::Ref(.., ty::Mutability::Not)
)
}))
// (2.)
|| matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::Mutable))
}

View file

@ -16,6 +16,7 @@ Rust lexer used by rustc. No stability guarantees are provided.
[dependencies]
memchr = "2.7.4"
unicode-xid = "0.2.0"
literal-escaper = { path = "../../library/literal-escaper" }
[dependencies.unicode-properties]
version = "0.1.0"

View file

@ -26,11 +26,13 @@
// tidy-alphabetical-end
mod cursor;
pub mod unescape;
#[cfg(test)]
mod tests;
// FIXME: This is needed for rust-analyzer. Remove this dependency once rust-analyzer uses
// `literal-escaper`.
pub use literal_escaper as unescape;
use unicode_properties::UnicodeEmoji;
pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;

View file

@ -843,9 +843,8 @@ fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> b
}
}
}
} else if attr.path().starts_with(&[sym::diagnostic]) && attr.path().len() == 2 {
should_encode =
rustc_feature::is_stable_diagnostic_attribute(attr.path()[1], state.features);
} else if let &[sym::diagnostic, seg] = &*attr.path() {
should_encode = rustc_feature::is_stable_diagnostic_attribute(seg, state.features);
} else {
should_encode = true;
}

View file

@ -641,21 +641,19 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
}
}
Alias(Projection, AliasTy { def_id, .. }) => {
if self.tcx.def_kind(def_id) != DefKind::AssocTy {
return ControlFlow::Break(());
}
Alias(Projection, AliasTy { def_id, .. })
if self.tcx.def_kind(def_id) != DefKind::AssocTy =>
{
return ControlFlow::Break(());
}
Param(param) => {
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
// sufficient info to determine if it is synthetic, and we don't
// always have a convenient way of getting `ty::Generics` at the call
// sites we invoke `IsSuggestable::is_suggestable`.
if param.name.as_str().starts_with("impl ") {
return ControlFlow::Break(());
}
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
// sufficient info to determine if it is synthetic, and we don't
// always have a convenient way of getting `ty::Generics` at the call
// sites we invoke `IsSuggestable::is_suggestable`.
Param(param) if param.name.as_str().starts_with("impl ") => {
return ControlFlow::Break(());
}
_ => {}
@ -733,17 +731,13 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
}
}
Param(param) => {
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
// sufficient info to determine if it is synthetic, and we don't
// always have a convenient way of getting `ty::Generics` at the call
// sites we invoke `IsSuggestable::is_suggestable`.
if param.name.as_str().starts_with("impl ") {
return Err(());
}
t
// FIXME: It would be nice to make this not use string manipulation,
// but it's pretty hard to do this, since `ty::ParamTy` is missing
// sufficient info to determine if it is synthetic, and we don't
// always have a convenient way of getting `ty::Generics` at the call
// sites we invoke `IsSuggestable::is_suggestable`.
Param(param) if param.name.as_str().starts_with("impl ") => {
return Err(());
}
_ => t,

View file

@ -6,6 +6,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
literal-escaper = { path = "../../library/literal-escaper" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }

View file

@ -1,12 +1,12 @@
use std::ops::Range;
use literal_escaper::{self, EscapeError, Mode};
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
use rustc_lexer::unescape::{self, EscapeError, Mode};
use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
@ -970,7 +970,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
postfix_len: u32,
) -> (token::LitKind, Symbol) {
self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
unescape::unescape_unicode(src, mode, &mut |span, result| {
literal_escaper::unescape_unicode(src, mode, &mut |span, result| {
callback(span, result.map(drop))
})
})
@ -986,7 +986,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
postfix_len: u32,
) -> (token::LitKind, Symbol) {
self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
unescape::unescape_mixed(src, mode, &mut |span, result| {
literal_escaper::unescape_mixed(src, mode, &mut |span, result| {
callback(span, result.map(drop))
})
})

View file

@ -3,8 +3,8 @@
use std::iter::once;
use std::ops::Range;
use literal_escaper::{EscapeError, Mode};
use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed};
use rustc_lexer::unescape::{EscapeError, Mode};
use rustc_span::{BytePos, Span};
use tracing::debug;

View file

@ -6,6 +6,7 @@ use core::ops::{Bound, ControlFlow};
use ast::mut_visit::{self, MutVisitor};
use ast::token::{IdentIsRaw, MetaVarKind};
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
use literal_escaper::unescape_char;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenTree;
@ -21,7 +22,6 @@ use rustc_ast::{
use rustc_ast_pretty::pprust;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
use rustc_lexer::unescape::unescape_char;
use rustc_macros::Subdiagnostic;
use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
use rustc_session::lint::BuiltinLintDiag;

View file

@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
literal-escaper = { path = "../../library/literal-escaper" }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_lexer = { path = "../rustc_lexer" }
# tidy-alphabetical-end

View file

@ -18,7 +18,6 @@
pub use Alignment::*;
pub use Count::*;
pub use Position::*;
use rustc_lexer::unescape;
// Note: copied from rustc_span
/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
@ -1094,12 +1093,14 @@ fn find_width_map_from_snippet(
fn unescape_string(string: &str) -> Option<String> {
let mut buf = String::new();
let mut ok = true;
unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| {
match unescaped_char {
literal_escaper::unescape_unicode(
string,
literal_escaper::Mode::Str,
&mut |_, unescaped_char| match unescaped_char {
Ok(c) => buf.push(c),
Err(_) => ok = false,
}
});
},
);
ok.then_some(buf)
}

View file

@ -1132,7 +1132,7 @@ impl<'tcx> DeadVisitor<'tcx> {
return;
}
dead_codes.sort_by_key(|v| v.level);
for group in dead_codes[..].chunk_by(|a, b| a.level == b.level) {
for group in dead_codes.chunk_by(|a, b| a.level == b.level) {
self.lint_at_single_level(&group, participle, Some(def_id), report_on);
}
}

View file

@ -18,7 +18,7 @@ pub(crate) fn target() -> Target {
description: Some("64-bit x86 Cygwin".into()),
tier: Some(3),
host_tools: Some(false),
std: None,
std: Some(true),
},
}
}

View file

@ -165,6 +165,13 @@ dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "literal-escaper"
version = "0.0.0"
dependencies = [
"rustc-std-workspace-std",
]
[[package]]
name = "memchr"
version = "2.7.4"
@ -236,6 +243,7 @@ name = "proc_macro"
version = "0.0.0"
dependencies = [
"core",
"literal-escaper",
"std",
]

View file

@ -8,6 +8,7 @@ members = [
]
exclude = [
"literal-escaper",
# stdarch has its own Cargo workspace
"stdarch",
"windows_targets"

View file

@ -84,9 +84,29 @@ macro_rules! acquire {
///
/// Shared references in Rust disallow mutation by default, and `Arc` is no
/// exception: you cannot generally obtain a mutable reference to something
/// inside an `Arc`. If you need to mutate through an `Arc`, use
/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic]
/// types.
/// inside an `Arc`. If you do need to mutate through an `Arc`, you have several options:
///
/// 1. Use interior mutability with synchronization primitives like [`Mutex`][mutex],
/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
///
/// 2. Use clone-on-write semantics with [`Arc::make_mut`] which provides efficient mutation
/// without requiring interior mutability. This approach clones the data only when
/// needed (when there are multiple references) and can be more efficient when mutations
/// are infrequent.
///
/// 3. Use [`Arc::get_mut`] when you know your `Arc` is not shared (has a reference count of 1),
/// which provides direct mutable access to the inner value without any cloning.
///
/// ```
/// use std::sync::Arc;
///
/// let mut data = Arc::new(vec![1, 2, 3]);
///
/// // This will clone the vector only if there are other references to it
/// Arc::make_mut(&mut data).push(4);
///
/// assert_eq!(*data, vec![1, 2, 3, 4]);
/// ```
///
/// **Note**: This type is only available on platforms that support atomic
/// loads and stores of pointers, which includes all platforms that support

View file

@ -0,0 +1,10 @@
[package]
name = "literal-escaper"
version = "0.0.0"
edition = "2021"
[dependencies]
std = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-std' }
[features]
rustc-dep-of-std = ["dep:std"]

View file

@ -0,0 +1,4 @@
# literal-escaper
This crate provides code to unescape string literals. It is used by `rustc_lexer`
and `proc_macro`.

View file

@ -4,6 +4,7 @@ version = "0.0.0"
edition = "2024"
[dependencies]
literal-escaper = { path = "../literal-escaper", features = ["rustc-dep-of-std"] }
std = { path = "../std" }
# Workaround: when documenting this crate rustdoc will try to load crate named
# `core` when resolving doc links. Without this line a different `core` will be

View file

@ -28,6 +28,7 @@
#![feature(restricted_std)]
#![feature(rustc_attrs)]
#![feature(extend_one)]
#![feature(stmt_expr_attributes)]
#![recursion_limit = "256"]
#![allow(internal_features)]
#![deny(ffi_unwind_calls)]
@ -51,11 +52,24 @@ use std::{error, fmt};
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
pub use diagnostic::{Diagnostic, Level, MultiSpan};
#[unstable(feature = "proc_macro_value", issue = "136652")]
pub use literal_escaper::EscapeError;
use literal_escaper::{MixedUnit, Mode, byte_from_char, unescape_mixed, unescape_unicode};
#[unstable(feature = "proc_macro_totokens", issue = "130977")]
pub use to_tokens::ToTokens;
use crate::escape::{EscapeOptions, escape_bytes};
/// Errors returned when trying to retrieve a literal unescaped value.
#[unstable(feature = "proc_macro_value", issue = "136652")]
#[derive(Debug, PartialEq, Eq)]
pub enum ConversionErrorKind {
/// The literal failed to be escaped, take a look at [`EscapeError`] for more information.
FailedToUnescape(EscapeError),
/// Trying to convert a literal with the wrong type.
InvalidLiteralKind,
}
/// Determines whether proc_macro has been made accessible to the currently
/// running program.
///
@ -1451,6 +1465,107 @@ impl Literal {
}
})
}
/// Returns the unescaped string value if the current literal is a string or a string literal.
#[unstable(feature = "proc_macro_value", issue = "136652")]
pub fn str_value(&self) -> Result<String, ConversionErrorKind> {
self.0.symbol.with(|symbol| match self.0.kind {
bridge::LitKind::Str => {
if symbol.contains('\\') {
let mut buf = String::with_capacity(symbol.len());
let mut error = None;
// Force-inlining here is aggressive but the closure is
// called on every char in the string, so it can be hot in
// programs with many long strings containing escapes.
unescape_unicode(
symbol,
Mode::Str,
&mut #[inline(always)]
|_, c| match c {
Ok(c) => buf.push(c),
Err(err) => {
if err.is_fatal() {
error = Some(ConversionErrorKind::FailedToUnescape(err));
}
}
},
);
if let Some(error) = error { Err(error) } else { Ok(buf) }
} else {
Ok(symbol.to_string())
}
}
bridge::LitKind::StrRaw(_) => Ok(symbol.to_string()),
_ => Err(ConversionErrorKind::InvalidLiteralKind),
})
}
/// Returns the unescaped string value if the current literal is a c-string or a c-string
/// literal.
#[unstable(feature = "proc_macro_value", issue = "136652")]
pub fn cstr_value(&self) -> Result<Vec<u8>, ConversionErrorKind> {
self.0.symbol.with(|symbol| match self.0.kind {
bridge::LitKind::CStr => {
let mut error = None;
let mut buf = Vec::with_capacity(symbol.len());
unescape_mixed(symbol, Mode::CStr, &mut |_span, c| match c {
Ok(MixedUnit::Char(c)) => {
buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
}
Ok(MixedUnit::HighByte(b)) => buf.push(b),
Err(err) => {
if err.is_fatal() {
error = Some(ConversionErrorKind::FailedToUnescape(err));
}
}
});
if let Some(error) = error {
Err(error)
} else {
buf.push(0);
Ok(buf)
}
}
bridge::LitKind::CStrRaw(_) => {
// Raw strings have no escapes so we can convert the symbol
// directly to a `Lrc<u8>` after appending the terminating NUL
// char.
let mut buf = symbol.to_owned().into_bytes();
buf.push(0);
Ok(buf)
}
_ => Err(ConversionErrorKind::InvalidLiteralKind),
})
}
/// Returns the unescaped string value if the current literal is a byte string or a byte string
/// literal.
#[unstable(feature = "proc_macro_value", issue = "136652")]
pub fn byte_str_value(&self) -> Result<Vec<u8>, ConversionErrorKind> {
self.0.symbol.with(|symbol| match self.0.kind {
bridge::LitKind::ByteStr => {
let mut buf = Vec::with_capacity(symbol.len());
let mut error = None;
unescape_unicode(symbol, Mode::ByteStr, &mut |_, c| match c {
Ok(c) => buf.push(byte_from_char(c)),
Err(err) => {
if err.is_fatal() {
error = Some(ConversionErrorKind::FailedToUnescape(err));
}
}
});
if let Some(error) = error { Err(error) } else { Ok(buf) }
}
bridge::LitKind::ByteStrRaw(_) => {
// Raw strings have no escapes so we can convert the symbol
// directly to a `Lrc<u8>`.
Ok(symbol.to_owned().into_bytes())
}
_ => Err(ConversionErrorKind::InvalidLiteralKind),
})
}
}
/// Parse a single literal from its stringified representation.

View file

@ -62,6 +62,7 @@ fn main() {
|| target_os == "zkvm"
|| target_os == "rtems"
|| target_os == "nuttx"
|| target_os == "cygwin"
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()

View file

@ -310,7 +310,7 @@ pub use self::error::RawOsError;
pub use self::error::SimpleMessage;
#[unstable(feature = "io_const_error", issue = "133448")]
pub use self::error::const_error;
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
pub use self::pipe::{PipeReader, PipeWriter, pipe};
#[stable(feature = "is_terminal", since = "1.70.0")]
pub use self::stdio::IsTerminal;

View file

@ -1,5 +1,6 @@
use crate::io;
use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
use crate::sys_common::{FromInner, IntoInner};
/// Create an anonymous pipe.
///
@ -40,7 +41,6 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
@ -67,29 +67,52 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
/// ```
/// [changes]: io#platform-specific-behavior
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
}
/// Read end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug)]
pub struct PipeReader(pub(crate) AnonPipe);
/// Write end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug)]
pub struct PipeWriter(pub(crate) AnonPipe);
impl FromInner<AnonPipe> for PipeReader {
fn from_inner(inner: AnonPipe) -> Self {
Self(inner)
}
}
impl IntoInner<AnonPipe> for PipeReader {
fn into_inner(self) -> AnonPipe {
self.0
}
}
impl FromInner<AnonPipe> for PipeWriter {
fn from_inner(inner: AnonPipe) -> Self {
Self(inner)
}
}
impl IntoInner<AnonPipe> for PipeWriter {
fn into_inner(self) -> AnonPipe {
self.0
}
}
impl PipeReader {
/// Create a new [`PipeReader`] instance that shares the same underlying file description.
///
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
@ -137,7 +160,7 @@ impl PipeReader {
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
@ -149,7 +172,6 @@ impl PipeWriter {
/// # Examples
///
/// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> {
@ -177,13 +199,13 @@ impl PipeWriter {
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl io::Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
@ -203,7 +225,7 @@ impl io::Read for &PipeReader {
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl io::Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
@ -223,7 +245,7 @@ impl io::Read for PipeReader {
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl io::Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
@ -241,7 +263,7 @@ impl io::Write for &PipeWriter {
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl io::Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)

View file

@ -0,0 +1,102 @@
#![stable(feature = "metadata_ext", since = "1.1.0")]
use crate::fs::Metadata;
use crate::sys_common::AsInner;
/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: crate::fs::Metadata
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_birthtime(&self) -> i64;
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_birthtime_nsec(&self) -> i64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn st_ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn st_ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
fn st_birthtime(&self) -> i64 {
self.as_inner().as_inner().st_birthtime as i64
}
fn st_birthtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_birthtime_nsec as i64
}
}

View file

@ -0,0 +1,4 @@
//! Cygwin-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod fs;
pub(crate) mod raw;

View file

@ -0,0 +1,4 @@
//! Cygwin-specific raw type definitions.
#[stable(feature = "raw_ext", since = "1.1.0")]
pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, pthread_t, time_t};

View file

@ -15,8 +15,9 @@ use crate::mem::ManuallyDrop;
target_os = "trusty"
)))]
use crate::sys::cvt;
use crate::sys_common::FromInner;
#[cfg(not(target_os = "trusty"))]
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::sys_common::{AsInner, IntoInner};
use crate::{fmt, io};
type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
@ -504,3 +505,45 @@ impl<'a> AsFd for io::StderrLock<'a> {
unsafe { BorrowedFd::borrow_raw(2) }
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsFd for io::PipeReader {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeReader> for OwnedFd {
fn from(pipe: io::PipeReader) -> Self {
pipe.0.into_inner()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsFd for io::PipeWriter {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeWriter> for OwnedFd {
fn from(pipe: io::PipeWriter) -> Self {
pipe.0.into_inner()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<OwnedFd> for io::PipeReader {
fn from(owned_fd: OwnedFd) -> Self {
Self(FromInner::from_inner(owned_fd))
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<OwnedFd> for io::PipeWriter {
fn from(owned_fd: OwnedFd) -> Self {
Self(FromInner::from_inner(owned_fd))
}
}

View file

@ -18,6 +18,7 @@ use crate::os::unix::io::AsFd;
use crate::os::unix::io::OwnedFd;
#[cfg(target_os = "wasi")]
use crate::os::wasi::io::OwnedFd;
use crate::sys_common::FromInner;
#[cfg(not(target_os = "trusty"))]
use crate::sys_common::{AsInner, IntoInner};
@ -284,3 +285,45 @@ impl<T: AsRawFd> AsRawFd for Box<T> {
(**self).as_raw_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsRawFd for io::PipeReader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl FromRawFd for io::PipeReader {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) })
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl IntoRawFd for io::PipeReader {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsRawFd for io::PipeWriter {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl FromRawFd for io::PipeWriter {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
Self::from_inner(unsafe { FromRawFd::from_raw_fd(raw_fd) })
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl IntoRawFd for io::PipeWriter {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}

View file

@ -125,6 +125,8 @@ pub mod windows;
pub mod aix;
#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "cygwin")]
pub mod cygwin;
#[cfg(target_os = "dragonfly")]
pub mod dragonfly;
#[cfg(target_os = "emscripten")]

View file

@ -41,6 +41,8 @@ mod platform {
pub use crate::os::aix::*;
#[cfg(target_os = "android")]
pub use crate::os::android::*;
#[cfg(target_os = "cygwin")]
pub use crate::os::cygwin::*;
#[cfg(target_vendor = "apple")]
pub use crate::os::darwin::*;
#[cfg(target_os = "dragonfly")]

View file

@ -9,6 +9,7 @@
target_os = "illumos",
target_os = "haiku",
target_os = "nto",
target_os = "cygwin"
))]
use libc::MSG_NOSIGNAL;
@ -37,6 +38,7 @@ use crate::{fmt, io};
target_os = "illumos",
target_os = "haiku",
target_os = "nto",
target_os = "cygwin"
)))]
const MSG_NOSIGNAL: core::ffi::c_int = 0x0;

View file

@ -21,6 +21,7 @@ mod tests;
target_os = "openbsd",
target_os = "nto",
target_vendor = "apple",
target_os = "cygwin"
))]
mod ucred;
@ -44,6 +45,7 @@ pub use self::stream::*;
target_os = "openbsd",
target_os = "nto",
target_vendor = "apple",
target_os = "cygwin",
))]
#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
pub use self::ucred::*;

View file

@ -10,6 +10,7 @@ use super::{SocketAncillary, recv_vectored_with_ancillary_from, send_vectored_wi
target_os = "openbsd",
target_os = "nto",
target_vendor = "apple",
target_os = "cygwin"
))]
use super::{UCred, peer_cred};
use crate::fmt;
@ -231,6 +232,7 @@ impl UnixStream {
target_os = "openbsd",
target_os = "nto",
target_vendor = "apple",
target_os = "cygwin"
))]
pub fn peer_cred(&self) -> io::Result<UCred> {
peer_cred(self)

View file

@ -33,10 +33,10 @@ pub(super) use self::impl_apple::peer_cred;
target_os = "nto"
))]
pub(super) use self::impl_bsd::peer_cred;
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg(any(target_os = "android", target_os = "linux", target_os = "cygwin"))]
pub(super) use self::impl_linux::peer_cred;
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg(any(target_os = "linux", target_os = "android", target_os = "cygwin"))]
mod impl_linux {
use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred};

View file

@ -660,3 +660,45 @@ impl<T> From<crate::thread::JoinHandle<T>> for OwnedHandle {
join_handle.into_inner().into_handle().into_inner()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsHandle for io::PipeReader {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeReader> for OwnedHandle {
fn from(pipe: io::PipeReader) -> Self {
pipe.into_inner().into_inner()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsHandle for io::PipeWriter {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeWriter> for OwnedHandle {
fn from(pipe: io::PipeWriter) -> Self {
pipe.into_inner().into_inner()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<OwnedHandle> for io::PipeReader {
fn from(owned_handle: OwnedHandle) -> Self {
Self::from_inner(FromInner::from_inner(owned_handle))
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<OwnedHandle> for io::PipeWriter {
fn from(owned_handle: OwnedHandle) -> Self {
Self::from_inner(FromInner::from_inner(owned_handle))
}
}

View file

@ -310,3 +310,45 @@ impl IntoRawSocket for net::UdpSocket {
self.into_inner().into_socket().into_inner().into_raw_socket()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsRawHandle for io::PipeReader {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl FromRawHandle for io::PipeReader {
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl IntoRawHandle for io::PipeReader {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl AsRawHandle for io::PipeWriter {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl FromRawHandle for io::PipeWriter {
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
unsafe { Self::from_inner(FromRawHandle::from_raw_handle(raw_handle)) }
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl IntoRawHandle for io::PipeWriter {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}

View file

@ -1659,6 +1659,20 @@ impl From<io::Stderr> for Stdio {
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeWriter> for Stdio {
fn from(pipe: io::PipeWriter) -> Self {
Stdio::from_inner(pipe.into_inner().into())
}
}
#[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
impl From<io::PipeReader> for Stdio {
fn from(pipe: io::PipeReader) -> Self {
Stdio::from_inner(pipe.into_inner().into())
}
}
/// Describes the result of a process after it has terminated.
///
/// This `struct` is used to represent the exit status or other termination of a child process.

View file

@ -37,7 +37,7 @@ use crate::sys::random as sys;
/// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html)
/// Vita | `arc4random_buf`
/// Hermit | `read_entropy`
/// Horizon | `getrandom` shim
/// Horizon, Cygwin | `getrandom`
/// AIX, Hurd, L4Re, QNX | `/dev/urandom`
/// Redox | `/scheme/rand`
/// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html)

View file

@ -1,9 +1,7 @@
use crate::io::{self, PipeReader, PipeWriter};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::process::Stdio;
use crate::io;
use crate::sys::fd::FileDesc;
use crate::sys::pipe::anon_pipe;
use crate::sys_common::{FromInner, IntoInner};
use crate::sys_common::IntoInner;
pub type AnonPipe = FileDesc;
@ -11,91 +9,3 @@ pub type AnonPipe = FileDesc;
pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner()))
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsFd for PipeReader {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawFd for PipeReader {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for OwnedFd {
fn from(pipe: PipeReader) -> Self {
FileDesc::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawFd for PipeReader {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self(FileDesc::from_raw_fd(raw_fd)) }
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawFd for PipeReader {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for Stdio {
fn from(pipe: PipeReader) -> Self {
Self::from(OwnedFd::from(pipe))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsFd for PipeWriter {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawFd for PipeWriter {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for OwnedFd {
fn from(pipe: PipeWriter) -> Self {
FileDesc::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawFd for PipeWriter {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self(FileDesc::from_raw_fd(raw_fd)) }
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawFd for PipeWriter {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for Stdio {
fn from(pipe: PipeWriter) -> Self {
Self::from(OwnedFd::from(pipe))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedFd> for PipeReader {
fn from(owned_fd: OwnedFd) -> Self {
Self(FileDesc::from_inner(owned_fd))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedFd> for PipeWriter {
fn from(owned_fd: OwnedFd) -> Self {
Self(FileDesc::from_inner(owned_fd))
}
}

View file

@ -1,22 +1,7 @@
use crate::io::{self, PipeReader, PipeWriter};
use crate::process::Stdio;
use crate::io;
pub use crate::sys::pipe::AnonPipe;
#[inline]
pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
Err(io::Error::UNSUPPORTED_PLATFORM)
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for Stdio {
fn from(pipe: PipeReader) -> Self {
pipe.0.diverge()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for Stdio {
fn from(pipe: PipeWriter) -> Self {
pipe.0.diverge()
}
}

View file

@ -1,12 +1,7 @@
use crate::io::{self, PipeReader, PipeWriter};
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
};
use crate::process::Stdio;
use crate::ptr;
use crate::os::windows::io::FromRawHandle;
use crate::sys::c;
use crate::sys::handle::Handle;
use crate::sys_common::{FromInner, IntoInner};
use crate::{io, ptr};
pub type AnonPipe = Handle;
@ -22,95 +17,3 @@ pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
unsafe { Ok((Handle::from_raw_handle(read_pipe), Handle::from_raw_handle(write_pipe))) }
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsHandle for PipeReader {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawHandle for PipeReader {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawHandle for PipeReader {
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
unsafe { Self(Handle::from_raw_handle(raw_handle)) }
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawHandle for PipeReader {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for OwnedHandle {
fn from(pipe: PipeReader) -> Self {
Handle::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeReader> for Stdio {
fn from(pipe: PipeReader) -> Self {
Self::from(OwnedHandle::from(pipe))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsHandle for PipeWriter {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl AsRawHandle for PipeWriter {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl FromRawHandle for PipeWriter {
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
unsafe { Self(Handle::from_raw_handle(raw_handle)) }
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl IntoRawHandle for PipeWriter {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for OwnedHandle {
fn from(pipe: PipeWriter) -> Self {
Handle::into_inner(pipe.0)
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<PipeWriter> for Stdio {
fn from(pipe: PipeWriter) -> Self {
Self::from(OwnedHandle::from(pipe))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedHandle> for PipeReader {
fn from(owned_handle: OwnedHandle) -> Self {
Self(Handle::from_inner(owned_handle))
}
}
#[unstable(feature = "anonymous_pipe", issue = "127154")]
impl From<OwnedHandle> for PipeWriter {
fn from(owned_handle: OwnedHandle) -> Self {
Self(Handle::from_inner(owned_handle))
}
}

View file

@ -543,7 +543,12 @@ impl FileAttr {
SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
}
#[cfg(any(target_os = "freebsd", target_os = "openbsd", target_vendor = "apple"))]
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_vendor = "apple",
target_os = "cygwin",
))]
pub fn created(&self) -> io::Result<SystemTime> {
SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64)
}
@ -553,6 +558,7 @@ impl FileAttr {
target_os = "openbsd",
target_os = "vita",
target_vendor = "apple",
target_os = "cygwin",
)))]
pub fn created(&self) -> io::Result<SystemTime> {
cfg_has_statx! {
@ -960,6 +966,7 @@ impl DirEntry {
#[cfg(any(
target_os = "linux",
target_os = "cygwin",
target_os = "emscripten",
target_os = "android",
target_os = "solaris",
@ -1220,6 +1227,7 @@ impl File {
target_os = "freebsd",
target_os = "fuchsia",
target_os = "linux",
target_os = "cygwin",
target_os = "android",
target_os = "netbsd",
target_os = "openbsd",
@ -1234,6 +1242,7 @@ impl File {
target_os = "fuchsia",
target_os = "freebsd",
target_os = "linux",
target_os = "cygwin",
target_os = "netbsd",
target_os = "openbsd",
target_os = "nto",

View file

@ -59,7 +59,8 @@ cfg_if::cfg_if! {
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
target_os = "solaris", target_os = "illumos",
target_os = "haiku", target_os = "nto"))] {
target_os = "haiku", target_os = "nto",
target_os = "cygwin"))] {
use libc::MSG_NOSIGNAL;
} else {
const MSG_NOSIGNAL: c_int = 0x0;

View file

@ -81,6 +81,7 @@ impl Socket {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "nto",
target_os = "solaris",
))] {
@ -128,6 +129,7 @@ impl Socket {
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "nto",
))] {
// Like above, set cloexec atomically
@ -257,6 +259,7 @@ impl Socket {
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
))] {
unsafe {
let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
@ -421,6 +424,7 @@ impl Socket {
Ok(())
}
#[cfg(not(target_os = "cygwin"))]
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = libc::linger {
l_onoff: linger.is_some() as libc::c_int,
@ -430,6 +434,16 @@ impl Socket {
setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger)
}
#[cfg(target_os = "cygwin")]
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = libc::linger {
l_onoff: linger.is_some() as libc::c_ushort,
l_linger: linger.unwrap_or_default().as_secs() as libc::c_ushort,
};
setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger)
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?;

View file

@ -100,6 +100,7 @@ impl DoubleEndedIterator for Args {
target_os = "dragonfly",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_os = "illumos",
target_os = "emscripten",

View file

@ -108,6 +108,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "cygwin")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "cygwin";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".dll";
pub const DLL_EXTENSION: &str = "dll";
pub const EXE_SUFFIX: &str = ".exe";
pub const EXE_EXTENSION: &str = "exe";
}
#[cfg(target_os = "android")]
pub mod os {
pub const FAMILY: &str = "unix";

View file

@ -47,6 +47,7 @@ const READ_LIMIT: usize = if cfg!(target_vendor = "apple") {
target_os = "netbsd",
target_os = "openbsd",
target_vendor = "apple",
target_os = "cygwin",
))]
const fn max_iov() -> usize {
libc::IOV_MAX as usize
@ -74,6 +75,7 @@ const fn max_iov() -> usize {
target_os = "horizon",
target_os = "vita",
target_vendor = "apple",
target_os = "cygwin",
)))]
const fn max_iov() -> usize {
16 // The minimum value required by POSIX.
@ -503,6 +505,7 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "cygwin",
target_os = "haiku",
target_os = "redox",
target_os = "vxworks",
@ -525,6 +528,7 @@ impl FileDesc {
target_os = "fuchsia",
target_os = "l4re",
target_os = "linux",
target_os = "cygwin",
target_os = "haiku",
target_os = "redox",
target_os = "vxworks",

View file

@ -380,7 +380,7 @@ cfg_if::cfg_if! {
#[link(name = "pthread")]
#[link(name = "rt")]
unsafe extern "C" {}
} else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] {
} else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd", target_os = "cygwin"))] {
#[link(name = "pthread")]
unsafe extern "C" {}
} else if #[cfg(target_os = "solaris")] {

View file

@ -46,6 +46,7 @@ unsafe extern "C" {
any(
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "android",
target_os = "redox",
target_os = "nuttx",
@ -118,7 +119,12 @@ pub fn error_string(errno: i32) -> String {
unsafe extern "C" {
#[cfg_attr(
all(
any(target_os = "linux", target_os = "hurd", target_env = "newlib"),
any(
target_os = "linux",
target_os = "hurd",
target_env = "newlib",
target_os = "cygwin"
),
not(target_env = "ohos")
),
link_name = "__xpg_strerror_r"
@ -395,6 +401,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
#[cfg(any(
target_os = "linux",
target_os = "cygwin",
target_os = "hurd",
target_os = "android",
target_os = "nuttx",

View file

@ -27,6 +27,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "redox"
))] {
unsafe {

View file

@ -489,6 +489,12 @@ impl From<AnonPipe> for Stdio {
}
}
impl From<FileDesc> for Stdio {
fn from(fd: FileDesc) -> Stdio {
Stdio::Fd(fd)
}
}
impl From<File> for Stdio {
fn from(file: File) -> Stdio {
Stdio::Fd(file.into_inner())

View file

@ -1157,7 +1157,7 @@ fn signal_string(signal: i32) -> &'static str {
)
))]
libc::SIGSTKFLT => " (SIGSTKFLT)",
#[cfg(any(target_os = "linux", target_os = "nto"))]
#[cfg(any(target_os = "linux", target_os = "nto", target_os = "cygwin"))]
libc::SIGPWR => " (SIGPWR)",
#[cfg(any(
target_os = "freebsd",
@ -1166,6 +1166,7 @@ fn signal_string(signal: i32) -> &'static str {
target_os = "dragonfly",
target_os = "nto",
target_vendor = "apple",
target_os = "cygwin",
))]
libc::SIGEMT => " (SIGEMT)",
#[cfg(any(

View file

@ -137,7 +137,8 @@ impl Thread {
target_os = "linux",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "nuttx"
target_os = "nuttx",
target_os = "cygwin"
))]
pub fn set_name(name: &CStr) {
unsafe {
@ -365,6 +366,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
target_os = "linux",
target_os = "aix",
target_vendor = "apple",
target_os = "cygwin",
))] {
#[allow(unused_assignments)]
#[allow(unused_mut)]

View file

@ -1,5 +1,6 @@
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::sys_common::{FromInner, IntoInner};
pub struct AnonPipe(!);
@ -54,3 +55,53 @@ impl AnonPipe {
pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
match p1.0 {}
}
impl FromInner<!> for AnonPipe {
fn from_inner(inner: !) -> Self {
inner
}
}
impl IntoInner<!> for AnonPipe {
fn into_inner(self) -> ! {
self.0
}
}
#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
mod unix_traits {
use super::AnonPipe;
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::sys_common::FromInner;
impl AsRawFd for AnonPipe {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
impl AsFd for AnonPipe {
fn as_fd(&self) -> BorrowedFd<'_> {
self.0
}
}
impl IntoRawFd for AnonPipe {
fn into_raw_fd(self) -> RawFd {
self.0
}
}
impl FromRawFd for AnonPipe {
unsafe fn from_raw_fd(_: RawFd) -> Self {
panic!("creating pipe on this platform is unsupported!")
}
}
impl FromInner<OwnedFd> for AnonPipe {
fn from_inner(_: OwnedFd) -> Self {
panic!("creating pipe on this platform is unsupported!")
}
}
}

View file

@ -621,6 +621,12 @@ impl From<AnonPipe> for Stdio {
}
}
impl From<Handle> for Stdio {
fn from(pipe: Handle) -> Stdio {
Stdio::Handle(pipe)
}
}
impl From<File> for Stdio {
fn from(file: File) -> Stdio {
Stdio::Handle(file.into_inner())

View file

@ -248,7 +248,10 @@ cfg_if::cfg_if! {
}
cfg_if::cfg_if! {
if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] {
if #[cfg(any(
all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
target_os = "cygwin",
))] {
/// personality fn called by [Windows Structured Exception Handling][windows-eh]
///
/// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH,

View file

@ -35,10 +35,10 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::fill_bytes;
} else if #[cfg(target_os = "horizon")] {
// FIXME: add arc4random_buf to shim-3ds
mod horizon;
pub use horizon::fill_bytes;
} else if #[cfg(any(target_os = "horizon", target_os = "cygwin"))] {
// FIXME(horizon): add arc4random_buf to shim-3ds
mod getrandom;
pub use getrandom::fill_bytes;
} else if #[cfg(any(
target_os = "aix",
target_os = "hurd",

View file

@ -1,5 +1,3 @@
#![feature(anonymous_pipe)]
fn main() {
#[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))]
{

View file

@ -27,10 +27,10 @@ pub type _Unwind_Trace_Fn =
#[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5;
#[cfg(all(target_arch = "x86_64", not(target_os = "windows")))]
#[cfg(all(target_arch = "x86_64", not(any(target_os = "windows", target_os = "cygwin"))))]
pub const unwinder_private_data_size: usize = 2;
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
#[cfg(all(target_arch = "x86_64", any(target_os = "windows", target_os = "cygwin")))]
pub const unwinder_private_data_size: usize = 6;
#[cfg(all(target_arch = "arm", not(target_vendor = "apple")))]
@ -289,7 +289,10 @@ if #[cfg(all(target_vendor = "apple", not(target_os = "watchos"), target_arch =
} // cfg_if!
cfg_if::cfg_if! {
if #[cfg(all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"))] {
if #[cfg(any(
all(windows, any(target_arch = "aarch64", target_arch = "x86_64"), target_env = "gnu"),
target_os = "cygwin",
))] {
// We declare these as opaque types. This is fine since you just need to
// pass them to _GCC_specific_handler and forget about them.
pub enum EXCEPTION_RECORD {}

View file

@ -655,7 +655,7 @@ mod dist {
let mut builder = Builder::new(&build);
builder.run_step_descriptions(
&Builder::get_step_descriptions(Kind::Build),
&["compiler/rustc".into(), "library".into()],
&["compiler/rustc".into(), "std".into()],
);
assert_eq!(builder.config.stage, 2);

View file

@ -62,6 +62,11 @@ pub fn build(build: &mut Build) {
let relative_path = krate.local_path(build);
build.crates.insert(name.clone(), krate);
let existing_path = build.crate_paths.insert(relative_path, name);
// `literal-escaper` is both a dependency of `compiler/rustc_lexer` and of
// `library/proc-macro`, making it appear multiple times in the workspace.
if existing_path.as_deref() == Some("literal-escaper") {
continue;
}
assert!(
existing_path.is_none(),
"multiple crates with the same path: {}",

View file

@ -716,7 +716,7 @@ impl Build {
features.push("llvm");
}
// keep in sync with `bootstrap/compile.rs:rustc_cargo_env`
if self.config.rust_randomize_layout {
if self.config.rust_randomize_layout && check("rustc_randomized_layouts") {
features.push("rustc_randomized_layouts");
}

View file

@ -383,6 +383,6 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
ChangeInfo {
change_id: 137147,
severity: ChangeSeverity::Info,
summary: "New option `build.exclude` that adds support for excluding test.",
summary: "Added new option `build.exclude` which works the same way as `--exclude` flag on `x`.",
},
];

View file

@ -407,7 +407,7 @@ target | std | host | notes
[`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI)
[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS
[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator
[`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ? | | 64-bit x86 Cygwin |
[`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | | | 64-bit x86 Cygwin |
[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) |
[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) |
[`x86_64-pc-nto-qnx800`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 8.0 RTOS |

View file

@ -0,0 +1,55 @@
# `register_tool`
The tracking issue for this feature is: [#66079]
[#66079]: https://github.com/rust-lang/rust/issues/66079
------------------------
The `register_tool` language feature informs the compiler that attributes in your code are meant to be used with tools other than the compiler itself. This can be useful if your code has semantic meaning without the external tool, but enables additional features when the tool is present.
`register_tool` also allows configuring lint levels for external tools.
Tool attributes are only meant for ignorable attributes. If your code *changes* meaning when the attribute is present, it should not use a tool attribute (because it cannot be compiled with anything other than the external tool, and in a sense is a fork of the language).
------------------------
`#![register_tool(tool)]` is an attribute, and is only valid at the crate root.
Attributes using the registered tool are checked for valid syntax, and lint attributes are checked to be in a valid format. However, the compiler cannot validate the semantics of the attribute, nor can it tell whether the configured lint is present in the external tool.
Semantically, `clippy::*`, `rustdoc::*`, and `rustfmt::*` lints and attributes all behave as if `#![register_tool(clippy, rustdoc, rustfmt)]` were injected into the crate root, except that the `rustdoc` namespace can only be used for lints, not for attributes.
When compiling with `-Z unstable-features`, `rustc::*` lints can also be used. Like `rustdoc`, the `rustc` namespace can only be used with lints, not attributes.
The compiler will emit an error if it encounters a lint/attribute whose namespace isn't a registered tool.
Tool namespaces cannot be nested; `register_tool(main_tool::subtool)` is an error.
## Examples
Tool attributes:
```rust
#![feature(register_tool)]
#![register_tool(c2rust)]
// Mark which C header file this module was generated from.
#[c2rust::header_src = "operations.h"]
pub mod operations_h {
use std::ffi::c_int;
// Mark which source line this struct was generated from.
#[c2rust::src_loc = "11:0"]
pub struct Point {
pub x: c_int,
pub y: c_int,
}
}
```
Tool lints:
```
#![feature(register_tool)]
#![register_tool(bevy)]
#![deny(bevy::duplicate_bevy_dependencies)]
```

View file

@ -1,7 +1,5 @@
//@ignore-target: windows
#![feature(anonymous_pipe)]
use std::io::{Read, Write, pipe};
fn main() {

View file

@ -318,6 +318,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"libloading",
"linux-raw-sys",
"litemap",
"literal-escaper",
"lock_api",
"log",
"matchers",
@ -363,6 +364,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"rustc-rayon",
"rustc-rayon-core",
"rustc-stable-hash",
"rustc-std-workspace-std",
"rustc_apfloat",
"rustix",
"ruzstd", // via object in thorin-dwp

View file

@ -0,0 +1,46 @@
//@ edition: 2021
//@ check-pass
#![feature(impl_trait_in_bindings)]
struct FooS {
precise: i32,
}
fn ref_inside_mut(f: &mut &FooS) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn mut_inside_ref(f: &&mut FooS) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn mut_ref_inside_mut(f: &mut &mut FooS) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn ref_inside_box(f: Box<&FooS>) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn box_inside_ref(f: &Box<FooS>) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn box_inside_box(f: Box<Box<FooS>>) {
let x: impl AsyncFn() = async move || {
let y = &f.precise;
};
}
fn main() {}

View file

@ -0,0 +1,49 @@
//@ edition: 2021
#![feature(impl_trait_in_bindings)]
struct FooS {
precise: i32,
}
fn ref_inside_mut(f: &mut &FooS) {
let x: impl Fn() -> _ = async move || {
let y = &f.precise;
};
}
fn mut_inside_ref(f: &&mut FooS) {
let x: impl Fn() -> _ = async move || {
let y = &f.precise;
};
}
// Expected to fail, no immutable reference here.
fn mut_ref_inside_mut(f: &mut &mut FooS) {
let x: impl Fn() -> _ = async move || {
//~^ ERROR async closure does not implement `Fn`
let y = &f.precise;
};
}
fn ref_inside_box(f: Box<&FooS>) {
let x: impl Fn() -> _ = async move || {
let y = &f.precise;
};
}
fn box_inside_ref(f: &Box<FooS>) {
let x: impl Fn() -> _ = async move || {
let y = &f.precise;
};
}
// Expected to fail, no immutable reference here.
fn box_inside_box(f: Box<Box<FooS>>) {
let x: impl Fn() -> _ = async move || {
//~^ ERROR async closure does not implement `Fn`
let y = &f.precise;
};
}
fn main() {}

View file

@ -0,0 +1,14 @@
error: async closure does not implement `Fn` because it captures state from its environment
--> $DIR/imm-deref-not-lending.rs:23:29
|
LL | let x: impl Fn() -> _ = async move || {
| ^^^^^^^^^^^^^
error: async closure does not implement `Fn` because it captures state from its environment
--> $DIR/imm-deref-not-lending.rs:43:29
|
LL | let x: impl Fn() -> _ = async move || {
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -0,0 +1,3 @@
#![crate_type = "lib"]
extern crate literal_escaper; //~ ERROR

View file

@ -0,0 +1,13 @@
error[E0658]: use of unstable library feature `rustc_private`: this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
--> $DIR/literal-escaper.rs:3:1
|
LL | extern crate literal_escaper;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
= help: add `#![feature(rustc_private)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,10 +1,11 @@
// ignore-tidy-linelength
use proc_macro::Literal;
use proc_macro::{ConversionErrorKind, Literal};
pub fn test() {
test_display_literal();
test_parse_literal();
test_str_value_methods();
}
fn test_display_literal() {
@ -81,3 +82,53 @@ fn test_parse_literal() {
assert!("- 10".parse::<Literal>().is_err());
assert!("-'x'".parse::<Literal>().is_err());
}
fn test_str_value_methods() {
// Testing `str_value`
let lit = "\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.str_value(), Ok("\n".to_string()));
let lit = "r#\"\n\"#".parse::<Literal>().unwrap();
assert_eq!(lit.str_value(), Ok("\n".to_string()));
let lit = "1".parse::<Literal>().unwrap();
assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "b\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "c\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
// Testing `cstr_value`
let lit = "\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "r#\"\n\"#".parse::<Literal>().unwrap();
assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "1".parse::<Literal>().unwrap();
assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "b\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.cstr_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "c\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.cstr_value(), Ok(vec![b'\n', 0]));
// Testing `byte_str_value`
let lit = "\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "r#\"\n\"#".parse::<Literal>().unwrap();
assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "1".parse::<Literal>().unwrap();
assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
let lit = "b\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.byte_str_value(), Ok(vec![b'\n']));
let lit = "c\"\n\"".parse::<Literal>().unwrap();
assert_eq!(lit.byte_str_value(), Err(ConversionErrorKind::InvalidLiteralKind));
}

View file

@ -1,6 +1,7 @@
//@ edition: 2021
#![feature(proc_macro_span)]
#![feature(proc_macro_value)]
#![deny(dead_code)] // catch if a test function is never called
extern crate proc_macro;

View file

@ -0,0 +1,5 @@
//@ check-pass
//@ compile-flags: -Z crate-attr=feature(register_tool) -Z crate-attr=register_tool(foo)
#[allow(foo::bar)]
fn main() {}

View file

@ -0,0 +1,7 @@
//@ check-pass
#![feature(register_tool)]
#![register_tool(foo, bar, baz)]
#[allow(foo::a, bar::b, baz::c)]
fn main() {}

View file

@ -0,0 +1,4 @@
#![feature(register_tool)]
#![register_tool(foo::bar)] //~ ERROR only accepts identifiers
fn main() {}

View file

@ -0,0 +1,8 @@
error: `register_tool` only accepts identifiers
--> $DIR/nested-disallowed.rs:2:18
|
LL | #![register_tool(foo::bar)]
| ^^^^^^^^ not an identifier
error: aborting due to 1 previous error