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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
use std::{ascii, fmt, str}; 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, MixedUnit, Mode, byte_from_char, unescape_byte, unescape_char, unescape_mixed, unescape_unicode,
}; };
use rustc_span::{Span, Symbol, kw, sym}; use rustc_span::{Span, Symbol, kw, sym};

View file

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

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 // If `#[link_section]` is missing, then nothing to verify
let attrs = tcx.codegen_fn_attrs(id); let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
if attrs.link_section.is_none() {
return; return;
} };
// For the wasm32 target statics with `#[link_section]` other than `.init_array` // 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 // 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. // continue to work, but would no longer be necessary.
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
&& alloc.inner().provenance().ptrs().len() != 0 && !alloc.inner().provenance().ptrs().is_empty()
&& attrs && !link_section.as_str().starts_with(".init_array")
.link_section
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
.unwrap()
{ {
let msg = "statics with a custom `#[link_section]` must be a \ let msg = "statics with a custom `#[link_section]` must be a \
simple list of bytes on the wasm target with no \ simple list of bytes on the wasm target with no \

View file

@ -1532,10 +1532,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.may_coerce(blk_ty, *elem_ty) if self.may_coerce(blk_ty, *elem_ty)
&& blk.stmts.is_empty() && blk.stmts.is_empty()
&& blk.rules == hir::BlockCheckMode::DefaultBlock && 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( diag.multipart_suggestion_verbose(
"to create an array, use square brackets instead of curly braces", "to create an array, use square brackets instead of curly braces",
vec![ vec![
@ -1557,8 +1558,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
} }
}
}
#[instrument(skip(self, err))] #[instrument(skip(self, err))]
pub(crate) fn suggest_floating_point_literal( pub(crate) fn suggest_floating_point_literal(

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 /// (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 /// 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 /// apply a deref projection of an immutable reference, reborrows of immutable
/// captured by move. /// 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 /// ```rust
/// let x = &1i32; // Let's call this lifetime `'1`. /// let x = &1i32; // Let's call this lifetime `'1`.
@ -1902,10 +1903,22 @@ fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
) -> bool { ) -> bool {
// (1.) // (1.)
(!parent_capture.is_by_ref() (!parent_capture.is_by_ref()
&& !matches!( // This is just inlined `place.deref_tys()` but truncated to just
child_capture.place.projections.get(parent_capture.place.projections.len()), // the child projections. Namely, look for a `&T` deref, since we
Some(Projection { kind: ProjectionKind::Deref, .. }) // 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.) // (2.)
|| matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::Mutable)) || 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] [dependencies]
memchr = "2.7.4" memchr = "2.7.4"
unicode-xid = "0.2.0" unicode-xid = "0.2.0"
literal-escaper = { path = "../../library/literal-escaper" }
[dependencies.unicode-properties] [dependencies.unicode-properties]
version = "0.1.0" version = "0.1.0"

View file

@ -26,11 +26,13 @@
// tidy-alphabetical-end // tidy-alphabetical-end
mod cursor; mod cursor;
pub mod unescape;
#[cfg(test)] #[cfg(test)]
mod tests; 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; use unicode_properties::UnicodeEmoji;
pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; 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 { } else if let &[sym::diagnostic, seg] = &*attr.path() {
should_encode = should_encode = rustc_feature::is_stable_diagnostic_attribute(seg, state.features);
rustc_feature::is_stable_diagnostic_attribute(attr.path()[1], state.features);
} else { } else {
should_encode = true; should_encode = true;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1132,7 +1132,7 @@ impl<'tcx> DeadVisitor<'tcx> {
return; return;
} }
dead_codes.sort_by_key(|v| v.level); 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); 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()), description: Some("64-bit x86 Cygwin".into()),
tier: Some(3), tier: Some(3),
host_tools: Some(false), host_tools: Some(false),
std: None, std: Some(true),
}, },
} }
} }

View file

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

View file

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

View file

@ -84,9 +84,29 @@ macro_rules! acquire {
/// ///
/// Shared references in Rust disallow mutation by default, and `Arc` is no /// Shared references in Rust disallow mutation by default, and `Arc` is no
/// exception: you cannot generally obtain a mutable reference to something /// exception: you cannot generally obtain a mutable reference to something
/// inside an `Arc`. If you need to mutate through an `Arc`, use /// inside an `Arc`. If you do need to mutate through an `Arc`, you have several options:
/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] ///
/// types. /// 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 /// **Note**: This type is only available on platforms that support atomic
/// loads and stores of pointers, which includes all platforms that support /// 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" edition = "2024"
[dependencies] [dependencies]
literal-escaper = { path = "../literal-escaper", features = ["rustc-dep-of-std"] }
std = { path = "../std" } std = { path = "../std" }
# Workaround: when documenting this crate rustdoc will try to load crate named # 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 # `core` when resolving doc links. Without this line a different `core` will be

View file

@ -28,6 +28,7 @@
#![feature(restricted_std)] #![feature(restricted_std)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(extend_one)] #![feature(extend_one)]
#![feature(stmt_expr_attributes)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![allow(internal_features)] #![allow(internal_features)]
#![deny(ffi_unwind_calls)] #![deny(ffi_unwind_calls)]
@ -51,11 +52,24 @@ use std::{error, fmt};
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")] #[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
pub use diagnostic::{Diagnostic, Level, MultiSpan}; 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")] #[unstable(feature = "proc_macro_totokens", issue = "130977")]
pub use to_tokens::ToTokens; pub use to_tokens::ToTokens;
use crate::escape::{EscapeOptions, escape_bytes}; 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 /// Determines whether proc_macro has been made accessible to the currently
/// running program. /// 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. /// Parse a single literal from its stringified representation.

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use crate::io; use crate::io;
use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
use crate::sys_common::{FromInner, IntoInner};
/// Create an anonymous pipe. /// Create an anonymous pipe.
/// ///
@ -40,7 +41,6 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {} /// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))] /// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> { /// # fn main() -> std::io::Result<()> {
@ -67,29 +67,52 @@ use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner};
/// ``` /// ```
/// [changes]: io#platform-specific-behavior /// [changes]: io#platform-specific-behavior
/// [man page]: https://man7.org/linux/man-pages/man7/pipe.7.html /// [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] #[inline]
pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer)))
} }
/// Read end of an anonymous pipe. /// Read end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")] #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug)] #[derive(Debug)]
pub struct PipeReader(pub(crate) AnonPipe); pub struct PipeReader(pub(crate) AnonPipe);
/// Write end of an anonymous pipe. /// Write end of an anonymous pipe.
#[unstable(feature = "anonymous_pipe", issue = "127154")] #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
#[derive(Debug)] #[derive(Debug)]
pub struct PipeWriter(pub(crate) AnonPipe); 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 { impl PipeReader {
/// Create a new [`PipeReader`] instance that shares the same underlying file description. /// Create a new [`PipeReader`] instance that shares the same underlying file description.
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {} /// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))] /// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> { /// # fn main() -> std::io::Result<()> {
@ -137,7 +160,7 @@ impl PipeReader {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")] #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
pub fn try_clone(&self) -> io::Result<Self> { pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(Self) self.0.try_clone().map(Self)
} }
@ -149,7 +172,6 @@ impl PipeWriter {
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// #![feature(anonymous_pipe)]
/// # #[cfg(miri)] fn main() {} /// # #[cfg(miri)] fn main() {}
/// # #[cfg(not(miri))] /// # #[cfg(not(miri))]
/// # fn main() -> std::io::Result<()> { /// # fn main() -> std::io::Result<()> {
@ -177,13 +199,13 @@ impl PipeWriter {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[unstable(feature = "anonymous_pipe", issue = "127154")] #[stable(feature = "anonymous_pipe", since = "CURRENT_RUSTC_VERSION")]
pub fn try_clone(&self) -> io::Result<Self> { pub fn try_clone(&self) -> io::Result<Self> {
self.0.try_clone().map(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 { impl io::Read for &PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf) 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 { impl io::Read for PipeReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf) 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 { impl io::Write for &PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf) 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 { impl io::Write for PipeWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf) 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" target_os = "trusty"
)))] )))]
use crate::sys::cvt; use crate::sys::cvt;
use crate::sys_common::FromInner;
#[cfg(not(target_os = "trusty"))] #[cfg(not(target_os = "trusty"))]
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, IntoInner};
use crate::{fmt, io}; use crate::{fmt, io};
type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>; type ValidRawFd = core::num::niche_types::NotAllOnes<RawFd>;
@ -504,3 +505,45 @@ impl<'a> AsFd for io::StderrLock<'a> {
unsafe { BorrowedFd::borrow_raw(2) } 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; use crate::os::unix::io::OwnedFd;
#[cfg(target_os = "wasi")] #[cfg(target_os = "wasi")]
use crate::os::wasi::io::OwnedFd; use crate::os::wasi::io::OwnedFd;
use crate::sys_common::FromInner;
#[cfg(not(target_os = "trusty"))] #[cfg(not(target_os = "trusty"))]
use crate::sys_common::{AsInner, IntoInner}; use crate::sys_common::{AsInner, IntoInner};
@ -284,3 +285,45 @@ impl<T: AsRawFd> AsRawFd for Box<T> {
(**self).as_raw_fd() (**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; pub mod aix;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub mod android; pub mod android;
#[cfg(target_os = "cygwin")]
pub mod cygwin;
#[cfg(target_os = "dragonfly")] #[cfg(target_os = "dragonfly")]
pub mod dragonfly; pub mod dragonfly;
#[cfg(target_os = "emscripten")] #[cfg(target_os = "emscripten")]

View file

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

View file

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

View file

@ -21,6 +21,7 @@ mod tests;
target_os = "openbsd", target_os = "openbsd",
target_os = "nto", target_os = "nto",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin"
))] ))]
mod ucred; mod ucred;
@ -44,6 +45,7 @@ pub use self::stream::*;
target_os = "openbsd", target_os = "openbsd",
target_os = "nto", target_os = "nto",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin",
))] ))]
#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
pub use self::ucred::*; 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 = "openbsd",
target_os = "nto", target_os = "nto",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin"
))] ))]
use super::{UCred, peer_cred}; use super::{UCred, peer_cred};
use crate::fmt; use crate::fmt;
@ -231,6 +232,7 @@ impl UnixStream {
target_os = "openbsd", target_os = "openbsd",
target_os = "nto", target_os = "nto",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin"
))] ))]
pub fn peer_cred(&self) -> io::Result<UCred> { pub fn peer_cred(&self) -> io::Result<UCred> {
peer_cred(self) peer_cred(self)

View file

@ -33,10 +33,10 @@ pub(super) use self::impl_apple::peer_cred;
target_os = "nto" target_os = "nto"
))] ))]
pub(super) use self::impl_bsd::peer_cred; 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; 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 { mod impl_linux {
use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred}; 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() 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() 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. /// 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. /// 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) /// Solaris | [`arc4random_buf`](https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html)
/// Vita | `arc4random_buf` /// Vita | `arc4random_buf`
/// Hermit | `read_entropy` /// Hermit | `read_entropy`
/// Horizon | `getrandom` shim /// Horizon, Cygwin | `getrandom`
/// AIX, Hurd, L4Re, QNX | `/dev/urandom` /// AIX, Hurd, L4Re, QNX | `/dev/urandom`
/// Redox | `/scheme/rand` /// Redox | `/scheme/rand`
/// RTEMS | [`arc4random_buf`](https://docs.rtems.org/branches/master/bsp-howto/getentropy.html) /// 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::io;
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use crate::process::Stdio;
use crate::sys::fd::FileDesc; use crate::sys::fd::FileDesc;
use crate::sys::pipe::anon_pipe; use crate::sys::pipe::anon_pipe;
use crate::sys_common::{FromInner, IntoInner}; use crate::sys_common::IntoInner;
pub type AnonPipe = FileDesc; pub type AnonPipe = FileDesc;
@ -11,91 +9,3 @@ pub type AnonPipe = FileDesc;
pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) 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::io;
use crate::process::Stdio;
pub use crate::sys::pipe::AnonPipe; pub use crate::sys::pipe::AnonPipe;
#[inline] #[inline]
pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> {
Err(io::Error::UNSUPPORTED_PLATFORM) 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::FromRawHandle;
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
};
use crate::process::Stdio;
use crate::ptr;
use crate::sys::c; use crate::sys::c;
use crate::sys::handle::Handle; use crate::sys::handle::Handle;
use crate::sys_common::{FromInner, IntoInner}; use crate::{io, ptr};
pub type AnonPipe = Handle; 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))) } 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) 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> { pub fn created(&self) -> io::Result<SystemTime> {
SystemTime::new(self.stat.st_birthtime as i64, self.stat.st_birthtime_nsec as i64) 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 = "openbsd",
target_os = "vita", target_os = "vita",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin",
)))] )))]
pub fn created(&self) -> io::Result<SystemTime> { pub fn created(&self) -> io::Result<SystemTime> {
cfg_has_statx! { cfg_has_statx! {
@ -960,6 +966,7 @@ impl DirEntry {
#[cfg(any( #[cfg(any(
target_os = "linux", target_os = "linux",
target_os = "cygwin",
target_os = "emscripten", target_os = "emscripten",
target_os = "android", target_os = "android",
target_os = "solaris", target_os = "solaris",
@ -1220,6 +1227,7 @@ impl File {
target_os = "freebsd", target_os = "freebsd",
target_os = "fuchsia", target_os = "fuchsia",
target_os = "linux", target_os = "linux",
target_os = "cygwin",
target_os = "android", target_os = "android",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
@ -1234,6 +1242,7 @@ impl File {
target_os = "fuchsia", target_os = "fuchsia",
target_os = "freebsd", target_os = "freebsd",
target_os = "linux", target_os = "linux",
target_os = "cygwin",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "nto", target_os = "nto",

View file

@ -59,7 +59,8 @@ cfg_if::cfg_if! {
target_os = "dragonfly", target_os = "freebsd", target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd", target_os = "openbsd", target_os = "netbsd",
target_os = "solaris", target_os = "illumos", 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; use libc::MSG_NOSIGNAL;
} else { } else {
const MSG_NOSIGNAL: c_int = 0x0; const MSG_NOSIGNAL: c_int = 0x0;

View file

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

View file

@ -108,6 +108,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = ""; 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")] #[cfg(target_os = "android")]
pub mod os { pub mod os {
pub const FAMILY: &str = "unix"; 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 = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin",
))] ))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
libc::IOV_MAX as usize libc::IOV_MAX as usize
@ -74,6 +75,7 @@ const fn max_iov() -> usize {
target_os = "horizon", target_os = "horizon",
target_os = "vita", target_os = "vita",
target_vendor = "apple", target_vendor = "apple",
target_os = "cygwin",
)))] )))]
const fn max_iov() -> usize { const fn max_iov() -> usize {
16 // The minimum value required by POSIX. 16 // The minimum value required by POSIX.
@ -503,6 +505,7 @@ impl FileDesc {
target_os = "fuchsia", target_os = "fuchsia",
target_os = "l4re", target_os = "l4re",
target_os = "linux", target_os = "linux",
target_os = "cygwin",
target_os = "haiku", target_os = "haiku",
target_os = "redox", target_os = "redox",
target_os = "vxworks", target_os = "vxworks",
@ -525,6 +528,7 @@ impl FileDesc {
target_os = "fuchsia", target_os = "fuchsia",
target_os = "l4re", target_os = "l4re",
target_os = "linux", target_os = "linux",
target_os = "cygwin",
target_os = "haiku", target_os = "haiku",
target_os = "redox", target_os = "redox",
target_os = "vxworks", target_os = "vxworks",

View file

@ -380,7 +380,7 @@ cfg_if::cfg_if! {
#[link(name = "pthread")] #[link(name = "pthread")]
#[link(name = "rt")] #[link(name = "rt")]
unsafe extern "C" {} 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")] #[link(name = "pthread")]
unsafe extern "C" {} unsafe extern "C" {}
} else if #[cfg(target_os = "solaris")] { } else if #[cfg(target_os = "solaris")] {

View file

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

View file

@ -27,6 +27,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
target_os = "linux", target_os = "linux",
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd", target_os = "openbsd",
target_os = "cygwin",
target_os = "redox" target_os = "redox"
))] { ))] {
unsafe { 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 { impl From<File> for Stdio {
fn from(file: File) -> Stdio { fn from(file: File) -> Stdio {
Stdio::Fd(file.into_inner()) Stdio::Fd(file.into_inner())

View file

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

View file

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

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::sys_common::{FromInner, IntoInner};
pub struct AnonPipe(!); 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<()> { pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
match p1.0 {} 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 { impl From<File> for Stdio {
fn from(file: File) -> Stdio { fn from(file: File) -> Stdio {
Stdio::Handle(file.into_inner()) Stdio::Handle(file.into_inner())

View file

@ -248,7 +248,10 @@ cfg_if::cfg_if! {
} }
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] /// personality fn called by [Windows Structured Exception Handling][windows-eh]
/// ///
/// On x86_64 and AArch64 MinGW targets, the unwinding mechanism is SEH, /// 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")] { } else if #[cfg(target_os = "hermit")] {
mod hermit; mod hermit;
pub use hermit::fill_bytes; pub use hermit::fill_bytes;
} else if #[cfg(target_os = "horizon")] { } else if #[cfg(any(target_os = "horizon", target_os = "cygwin"))] {
// FIXME: add arc4random_buf to shim-3ds // FIXME(horizon): add arc4random_buf to shim-3ds
mod horizon; mod getrandom;
pub use horizon::fill_bytes; pub use getrandom::fill_bytes;
} else if #[cfg(any( } else if #[cfg(any(
target_os = "aix", target_os = "aix",
target_os = "hurd", target_os = "hurd",

View file

@ -1,5 +1,3 @@
#![feature(anonymous_pipe)]
fn main() { fn main() {
#[cfg(all(not(miri), any(unix, windows), not(target_os = "emscripten")))] #[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")] #[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5; 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; 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; pub const unwinder_private_data_size: usize = 6;
#[cfg(all(target_arch = "arm", not(target_vendor = "apple")))] #[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::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 // We declare these as opaque types. This is fine since you just need to
// pass them to _GCC_specific_handler and forget about them. // pass them to _GCC_specific_handler and forget about them.
pub enum EXCEPTION_RECORD {} pub enum EXCEPTION_RECORD {}

View file

@ -655,7 +655,7 @@ mod dist {
let mut builder = Builder::new(&build); let mut builder = Builder::new(&build);
builder.run_step_descriptions( builder.run_step_descriptions(
&Builder::get_step_descriptions(Kind::Build), &Builder::get_step_descriptions(Kind::Build),
&["compiler/rustc".into(), "library".into()], &["compiler/rustc".into(), "std".into()],
); );
assert_eq!(builder.config.stage, 2); 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); let relative_path = krate.local_path(build);
build.crates.insert(name.clone(), krate); build.crates.insert(name.clone(), krate);
let existing_path = build.crate_paths.insert(relative_path, name); 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!( assert!(
existing_path.is_none(), existing_path.is_none(),
"multiple crates with the same path: {}", "multiple crates with the same path: {}",

View file

@ -716,7 +716,7 @@ impl Build {
features.push("llvm"); features.push("llvm");
} }
// keep in sync with `bootstrap/compile.rs:rustc_cargo_env` // 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"); features.push("rustc_randomized_layouts");
} }

View file

@ -383,6 +383,6 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
ChangeInfo { ChangeInfo {
change_id: 137147, change_id: 137147,
severity: ChangeSeverity::Info, 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) [`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-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-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`](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-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 | [`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 //@ignore-target: windows
#![feature(anonymous_pipe)]
use std::io::{Read, Write, pipe}; use std::io::{Read, Write, pipe};
fn main() { fn main() {

View file

@ -318,6 +318,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"libloading", "libloading",
"linux-raw-sys", "linux-raw-sys",
"litemap", "litemap",
"literal-escaper",
"lock_api", "lock_api",
"log", "log",
"matchers", "matchers",
@ -363,6 +364,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"rustc-rayon", "rustc-rayon",
"rustc-rayon-core", "rustc-rayon-core",
"rustc-stable-hash", "rustc-stable-hash",
"rustc-std-workspace-std",
"rustc_apfloat", "rustc_apfloat",
"rustix", "rustix",
"ruzstd", // via object in thorin-dwp "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 // ignore-tidy-linelength
use proc_macro::Literal; use proc_macro::{ConversionErrorKind, Literal};
pub fn test() { pub fn test() {
test_display_literal(); test_display_literal();
test_parse_literal(); test_parse_literal();
test_str_value_methods();
} }
fn test_display_literal() { fn test_display_literal() {
@ -81,3 +82,53 @@ fn test_parse_literal() {
assert!("- 10".parse::<Literal>().is_err()); assert!("- 10".parse::<Literal>().is_err());
assert!("-'x'".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 //@ edition: 2021
#![feature(proc_macro_span)] #![feature(proc_macro_span)]
#![feature(proc_macro_value)]
#![deny(dead_code)] // catch if a test function is never called #![deny(dead_code)] // catch if a test function is never called
extern crate proc_macro; 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