Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser {
.zip(iter::repeat(cx.attr_span))
}

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
check_macro_only(cx, attr_span);
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ impl NoArgsAttributeParser for TrackCallerParser {
const STABILITY: AttributeStability = AttributeStability::Stable;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
match cx.target {
Target::Fn => {
// `#[track_caller]` is not valid on weak lang items because they are called via
Expand Down Expand Up @@ -571,7 +571,7 @@ impl CombineAttributeParser for TargetFeatureParser {
parse_tf_attribute(cx, args)
}

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
// `#[target_feature]` is incompatible with lang item functions,
// except on WASM where calling target-feature functions is safe (see #84988).
if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl SingleAttributeParser for RustcForceInlineParser {
))
}

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
let Some(inline_span) = find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span)
else {
return;
Expand Down
31 changes: 28 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use rustc_abi::ExternAbi;
use rustc_ast::ItemKind;
use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
use rustc_attr_ir::*;
use rustc_errors::msg;
use rustc_feature::{AttributeStability, Features};
use rustc_lint_defs::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES};
use rustc_session::Session;
use rustc_session::diagnostics::feature_err;
use rustc_span::edition::Edition::Edition2024;
Expand All @@ -17,7 +19,7 @@ use crate::attributes::cfg::parse_cfg_entry;
use crate::diagnostics::{
AsNeededCompatibility, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName,
ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink,
InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple,
InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, Link, LinkFrameworkApple,
LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection,
RawDylibOnlyWindows, WholeArchiveNeedsStatic,
};
Expand Down Expand Up @@ -258,6 +260,29 @@ impl CombineAttributeParser for LinkParser {
import_name_type,
})
}

fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
if cx.target != Target::ForeignMod {
return;
}

let item = cx.target_item.expect("missing AST target item for Target::ForeignMod");
let ItemKind::ForeignMod(fm) = &item.kind else {
panic!("expected foreign module AST target item for Target::ForeignMod");
};
let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| {
abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| {
cx.dcx().span_delayed_bug(
abi.span,
"LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi",
);
ExternAbi::Rust
})
});
if matches!(abi, ExternAbi::Rust) {
cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span);
}
}
}

impl LinkParser {
Expand Down Expand Up @@ -584,7 +609,7 @@ impl NoArgsAttributeParser for FfiPureParser {
const STABILITY: AttributeStability = unstable!(ffi_pure);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`.
if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {
cx.emit_err(BothFfiConstAndPure { attr_span });
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl NoArgsAttributeParser for RustcPubTransparentParser {
const STABILITY: AttributeStability = unstable!(rustc_attrs);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
// `#[rustc_pub_transparent]` may only be applied to `#[repr(transparent)]` types.
let is_transparent = find_attr!(
cx.parsed_attrs,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl NoArgsAttributeParser for AllowInternalUnsafeParser {
const STABILITY: AttributeStability = unstable!(allow_internal_unsafe);
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
check_macro_only(cx, attr_span);
}
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub(crate) trait SingleAttributeParser: 'static {
/// combinations. `attr_span` is the span of this attribute.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

/// Use in combination with [`SingleAttributeParser`].
Expand Down Expand Up @@ -287,7 +287,7 @@ pub(crate) trait NoArgsAttributeParser: 'static {
/// `attr_span` is the span of this attribute.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

pub(crate) struct WithoutArgs<T: NoArgsAttributeParser>(PhantomData<T>);
Expand All @@ -311,7 +311,7 @@ impl<T: NoArgsAttributeParser> SingleAttributeParser for WithoutArgs<T> {
Some(T::CREATE(cx.attr_span))
}

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
T::finalize_check(cx, attr_span)
}
}
Expand Down Expand Up @@ -355,7 +355,7 @@ pub(crate) trait CombineAttributeParser: 'static {
/// `attr_span` is the span of the first attribute that was encountered.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

/// Use in combination with [`CombineAttributeParser`].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser {
const STABILITY: AttributeStability = AttributeStability::Stable;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive;

fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
if cx.target != Target::Struct {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub(crate) type FinalizeFn = fn(&mut FinalizeContext<'_, '_>) -> FinalizeOutput;
/// finalized, so it can inspect the fully parsed attributes via
/// [`FinalizeCheckContext::parsed_attrs`]. The [`Span`] is the span of the attribute the
/// check is associated with, used for diagnostics.
pub(crate) type FinalizeCheckFn = fn(&FinalizeCheckContext<'_, '_>, Span);
pub(crate) type FinalizeCheckFn = fn(&mut FinalizeCheckContext<'_, '_>, Span);

/// The result of finalizing a single attribute parser.
pub(crate) struct FinalizeOutput {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,13 @@ pub(crate) struct EmptyLinkName {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("attribute should be applied to an `extern` block with non-Rust ABI")]
#[warning(
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
)]
pub(crate) struct Link;

#[derive(Diagnostic)]
#[diag("link kind `framework` is only supported on Apple targets", code = E0455)]
pub(crate) struct LinkFrameworkApple {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ impl<'sess> AttributeParser<'sess> {
// inspect the fully parsed attributes via `FinalizeCheckContext::parsed_attrs`.
for (check, attr_span) in deferred_checks {
check(
&FinalizeCheckContext {
&mut FinalizeCheckContext {
shared: SharedContext {
cx: self,
target_span,
Expand Down
19 changes: 1 addition & 18 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use std::cell::Cell;
use std::slice;

use rustc_abi::ExternAbi;
use rustc_ast::MetaItemKind;
use rustc_attr_ir::diagnostic::Directive;
use rustc_attr_ir::lang_items::LangItem;
Expand Down Expand Up @@ -208,7 +207,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
AttributeKind::Naked(..) => self.check_naked(hir_id, target),
AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target),
AttributeKind::MacroExport { span, .. } => {
self.check_macro_export(hir_id, *span, target)
}
Expand Down Expand Up @@ -271,6 +269,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttributeKind::InstructionSet(..) => (),
AttributeKind::InstrumentFn(..) => (),
AttributeKind::Lang(..) => (),
AttributeKind::Link(..) => (),
AttributeKind::LinkName { .. } => (),
AttributeKind::LinkOrdinal { .. } => (),
AttributeKind::LinkSection { .. } => (),
Expand Down Expand Up @@ -1100,22 +1099,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.dcx().emit_err(diagnostics::InvalidMayDangle { attr_span });
}

/// Checks if `#[link]` is applied to an item other than a foreign module.
fn check_link(&self, hir_id: HirId, attr_span: Span, target: Target) {
if target != Target::ForeignMod {
return; // Checked by attribute parser
}

if let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
&& !matches!(abi, ExternAbi::Rust)
{
return;
}

self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr_span, diagnostics::Link);
}

/// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
fn check_rustc_legacy_const_generics(
&self,
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,6 @@ pub(crate) struct BothOptimizeNoneAndInline {
pub inline_span: Span,
}

#[derive(Diagnostic)]
#[diag("attribute should be applied to an `extern` block with non-Rust ABI")]
#[warning(
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
)]
pub(crate) struct Link;

#[derive(Diagnostic)]
#[diag("#[rustc_legacy_const_generics] functions must only have const generics")]
pub(crate) struct RustcLegacyConstGenericsOnly {
Expand Down
36 changes: 36 additions & 0 deletions library/std/src/fs/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,42 @@ fn test_seek_read_buf() {
check!(fs::remove_file(&filename));
}

#[test]
#[cfg(windows)]
fn test_seek_read_buf_exact() {
use crate::os::windows::fs::FileExt;

let tmpdir = tmpdir();
let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf_exact.txt");
{
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
let mut file = check!(oo.open(&filename));
check!(file.write_all(b"0123456789"));
}
{
let mut file = check!(File::open(&filename));
let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
let mut buf = BorrowedBuf::from(buf.as_mut_slice());

// Exact read
check!(file.seek_read_buf_exact(buf.unfilled(), 2));
assert_eq!(buf.filled(), b"23456");
assert_eq!(check!(file.stream_position()), 7);

// Already full
check!(file.seek_read_buf_exact(buf.unfilled(), 3));
check!(file.seek_read_buf_exact(buf.unfilled(), 10));
assert_eq!(buf.filled(), b"23456");
assert_eq!(check!(file.stream_position()), 10);

// Non-empty exact read past eof fails
let err = file.seek_read_buf_exact(buf.clear().unfilled(), 6).unwrap_err();
assert_eq!(err.kind(), ErrorKind::UnexpectedEof);
assert_eq!(check!(file.stream_position()), 10);
}
check!(fs::remove_file(&filename));
}

#[test]
fn file_test_read_buf() {
let tmpdir = tmpdir();
Expand Down
57 changes: 57 additions & 0 deletions library/std/src/os/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,63 @@ pub trait FileExt {
io::default_read_buf(|b| self.seek_read(b, offset), buf)
}

/// Seeks to a given position and reads the exact number of bytes required to fill `buf`.
///
/// This is equivalent to the [`seek_read_exact`](FileExt::seek_read_exact) method, except
/// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use with
/// uninitialized buffers. The new data will be appended to any existing contents of `buf`.
///
/// Reading beyond the end of the file will always succeed without reading any bytes.
///
/// # Examples
///
#[cfg_attr(windows, doc = "```no_run")]
#[cfg_attr(not(windows), doc = "```ignore (needs windows)")]
/// #![feature(core_io_borrowed_buf)]
/// #![feature(read_buf_at)]
/// #![feature(seek_read_exact_seek_write_all)]
///
/// use std::io;
/// use std::io::BorrowedBuf;
/// use std::fs::File;
/// use std::mem::MaybeUninit;
/// use std::os::windows::prelude::*;
///
/// fn main() -> io::Result<()> {
/// let mut file = File::open("pi.txt")?;
///
/// // Read some bytes starting from offset 2
/// let mut buf: [MaybeUninit<u8>; 10] = [MaybeUninit::uninit(); 10];
/// let mut buf = BorrowedBuf::from(buf.as_mut_slice());
/// file.seek_read_buf_exact(buf.unfilled(), 2)?;
///
/// assert!(buf.filled().starts_with(b"1"));
///
/// Ok(())
/// }
/// ```
#[unstable(feature = "seek_read_exact_seek_write_all", issue = "162868")]
fn seek_read_buf_exact(
&self,
mut buf: BorrowedCursor<'_, u8>,
mut offset: u64,
) -> io::Result<()> {
while buf.capacity() > 0 {
let prev_written = buf.written();
match self.seek_read_buf(buf.reborrow(), offset) {
Ok(()) => {}
Err(e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
let n = buf.written() - prev_written;
offset += n as u64;
if n == 0 {
return Err(io::Error::READ_EXACT_EOF);
}
}
Ok(())
}

/// Seeks to a given position and writes a number of bytes.
///
/// Returns the number of bytes written.
Expand Down
16 changes: 10 additions & 6 deletions library/std/src/sys/fd/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,16 @@ pub struct FileDesc(OwnedFd);
//
// On Apple targets however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than INT_MAX. To handle both of these the read size is capped on
// both platforms.
const READ_LIMIT: usize = if cfg!(target_vendor = "apple") {
libc::c_int::MAX as usize
} else {
libc::ssize_t::MAX as usize
// larger than INT_MAX.
//
// Meanwhile on QNX, reads/writes/sends larger than INT_MAX return the wrong
// number of bytes written (eg, writing 2^31 bytes returns (2^64 - 2^31) instead
// of the correct byte count).
const READ_LIMIT: usize = cfg_select! {
any(target_vendor = "apple", target_os = "nto", target_os = "qnx") => {
libc::c_int::MAX as usize
}
_ => libc::ssize_t::MAX as usize,
};

#[cfg(any(
Expand Down
Loading
Loading