Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b1a5d85
Filter host libstdc++ ABI flag in rustc_llvm cross builds
chitao1234 Jul 5, 2026
8a07fcc
fix base_urls with periods
uselessgoddess Jul 18, 2026
a99f2dd
Remove extra semicolons in parsing item lists
chenyukang Jul 19, 2026
4aae990
make suggestion verbose
chenyukang Jul 19, 2026
d034826
Suggest close compiler options
chenyukang Jul 18, 2026
e46cf87
Extract coroutine_closure_output_coroutine.
cjgillot May 31, 2026
2a4115d
Extract pretty_print_closure_inner.
cjgillot Jun 1, 2026
f6d8df8
Move `std::io::buffered` to `alloc::io`
bushrat011899 May 12, 2026
f415df6
Reduce API surface of `Buffer`
bushrat011899 May 25, 2026
4af788e
Reduce API surface of `alloc::io::util`
bushrat011899 Jul 19, 2026
4f8a2a9
Reduce API surface of `alloc::io::read`
bushrat011899 Jul 19, 2026
44d9de2
Reduce API surface of `alloc::io` reexports from `core::io`
bushrat011899 Jul 19, 2026
f012e40
Use `String::try_push_str` instead of `unsafe` code
bushrat011899 Jul 20, 2026
295f7f4
Use `Vec::<u8>::try_extend_from_slice_of_bytes` instead of `unsafe` code
bushrat011899 Jul 20, 2026
3739d04
Make `Buffer` private
bushrat011899 Jul 20, 2026
69b3806
Standardize on `pub(super)` instead of `pub(in crate::io)`
bushrat011899 Jul 20, 2026
9d38fe5
Add `inline` to new `BufReader` method
bushrat011899 Jul 20, 2026
6ef1cf3
Add `inline` to new `BufWriter` method
bushrat011899 Jul 20, 2026
497bdc7
Update tests/ui/traits/next-solver/closure-capture-in-loop-120328.rs
SumkaKiller Jul 16, 2026
9204d14
ergonomic_clones_dotuse_capture_by_ref: Capture upvar by ref for `.us…
Dnreikronos Jul 20, 2026
192ce21
Make parsed attributes available in `finalize_check`
obeis Jun 28, 2026
d2777f4
Move `check_rustc_pub_transparent` into attribute parser
obeis Jun 28, 2026
02076ac
Add `FinalizeCheckContext` for attribute parser
obeis Jul 10, 2026
8c6aba0
Set the rustc lib path for unstable-book-gen
cuviper Jul 20, 2026
df3ea14
Clarify the comment about stage1/stage2 discrepancy in input-stats test
panstromek Jul 20, 2026
c4bda51
Support creating float constants in rustc_public mir
hkalbasi Jul 20, 2026
3f2624e
Make `TokenTreeCursor` private
nnethercote Jul 19, 2026
73de522
Make `TokenStream`'s internals private
nnethercote Jul 20, 2026
30bc6d2
fix: improve missing value diagnostics for built-in attributes
TorinAsakura Jul 20, 2026
e1d8ba6
Rollup merge of #159307 - TorinAsakura:fix/builtin-attribute-value-di…
jhpratt Jul 21, 2026
18b6b90
Rollup merge of #159543 - chenyukang:yukang-fix-159542-remove-extra-s…
jhpratt Jul 21, 2026
0f8d455
Rollup merge of #157270 - Dnreikronos:ergonomic_clones_dotuse_capture…
jhpratt Jul 21, 2026
3071eb4
Rollup merge of #158496 - obeis:move-check-rustc-pub-transparen, r=Jo…
jhpratt Jul 21, 2026
3425124
Rollup merge of #158547 - bushrat011899:alloc_io_buffered, r=clarfonthey
jhpratt Jul 21, 2026
5f9254e
Rollup merge of #158808 - chitao1234:fix-rustc-llvm-cross-libstdcxx-a…
jhpratt Jul 21, 2026
7152743
Rollup merge of #159362 - SumkaKiller:add-test-120328, r=adwinwhite
jhpratt Jul 21, 2026
f651441
Rollup merge of #159472 - hkalbasi:rustc_public_float, r=celinval
jhpratt Jul 21, 2026
652b5ed
Rollup merge of #159505 - uselessgoddess:fix/issue-159480, r=lolbinar…
jhpratt Jul 21, 2026
c390924
Rollup merge of #159568 - chenyukang:yukang-fix-159482-cli-option-typ…
jhpratt Jul 21, 2026
c89a1b3
Rollup merge of #159578 - cjgillot:coroutine-refactor, r=oli-obk
jhpratt Jul 21, 2026
d2f94b7
Rollup merge of #159601 - nnethercote:privatize-TokenTreeCursor, r=Ko…
jhpratt Jul 21, 2026
55804bd
Rollup merge of #159613 - cuviper:unstable-book-rpath, r=clubby789
jhpratt Jul 21, 2026
334b250
Rollup merge of #159616 - panstromek:clarify-input-stats-layout-chang…
jhpratt Jul 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
68 changes: 59 additions & 9 deletions compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ pub enum Spacing {

/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
pub struct TokenStream(Arc<Vec<TokenTree>>);

impl TokenStream {
pub fn new(tts: Vec<TokenTree>) -> TokenStream {
Expand Down Expand Up @@ -881,7 +881,7 @@ impl<'t> Iterator for TokenStreamIter<'t> {
}

#[derive(Clone, Debug)]
pub struct TokenTreeCursor {
struct TokenTreeCursor {
stream: TokenStream,
/// Points to the current token tree in the stream. In `TokenCursor::curr`,
/// this can be any token tree. In `TokenCursor::stack`, this is always a
Expand All @@ -891,27 +891,27 @@ pub struct TokenTreeCursor {

impl TokenTreeCursor {
#[inline]
pub fn new(stream: TokenStream) -> Self {
fn new(stream: TokenStream) -> Self {
TokenTreeCursor { stream, index: 0 }
}

#[inline]
pub fn curr(&self) -> Option<&TokenTree> {
fn curr(&self) -> Option<&TokenTree> {
self.stream.get(self.index)
}

pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
self.stream.get(self.index + n)
}

#[inline]
pub fn bump(&mut self) {
fn bump(&mut self) {
self.index += 1;
}

// For skipping ahead in rare circumstances.
#[inline]
pub fn bump_to_end(&mut self) {
fn bump_to_end(&mut self) {
self.index = self.stream.len();
}
}
Expand All @@ -927,18 +927,68 @@ pub struct TokenCursor {
// The delimiters for this token stream are found in `self.stack.last()`;
// if that is `None` we are in the outermost token stream which never has
// delimiters.
pub curr: TokenTreeCursor,
curr: TokenTreeCursor,

// Token streams surrounding the current one. The index within each cursor
// always points to a `TokenTree::Delimited`.
pub stack: Vec<TokenTreeCursor>,
stack: Vec<TokenTreeCursor>,
}

impl TokenCursor {
#[inline]
pub fn new(stream: TokenStream) -> Self {
TokenCursor { curr: TokenTreeCursor::new(stream), stack: vec![] }
}

pub fn next(&mut self) -> (Token, Spacing) {
self.inlined_next()
}

/// An `n` of zero is the next token tree in the current token stream; won't look outside the
/// current token stream.
#[inline]
pub fn look_ahead(&self, n: usize) -> Option<&TokenTree> {
self.curr.look_ahead(n)
}

/// Returns the first token tree (if there is one) past the close delimiter of the enclosing
/// delimited sequence. Panics if we are not within a delimited sequence.
#[inline]
pub fn look_ahead_past_close_delim(&self) -> Option<&TokenTree> {
self.stack.last().unwrap().look_ahead(1)
}

/// Clones the `TokenTree::Delimited` that we are currently within. Panics if we are not within
/// a delimited sequence.
#[inline]
pub fn clone_enclosing_delim(&self) -> TokenTree {
self.stack.last().unwrap().curr().unwrap().clone()
}

/// For skipping to the end of the current sequence, in rare circumstances.
#[inline]
pub fn bump_to_end(&mut self) {
self.curr.bump_to_end()
}

/// Note: the outermost stream has depth of 0.
#[inline]
pub fn depth(&self) -> usize {
self.stack.len()
}

/// Returns details about the parent delimited sequence, if there is one.
#[inline]
pub fn parent_delim_and_span(&self) -> Option<(Delimiter, DelimSpan)> {
if let Some(last) = self.stack.last()
&& let Some(TokenTree::Delimited(span, _, delim, _)) = last.curr()
{
Some((*delim, *span))
} else {
None
}
}

/// This always-inlined version should only be used on hot code paths.
#[inline(always)]
pub fn inlined_next(&mut self) -> (Token, Spacing) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ impl CombineAttributeParser for TargetFeatureParser {
parse_tf_attribute(cx, args)
}

fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &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/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ impl NoArgsAttributeParser for FfiPureParser {
const STABILITY: AttributeStability = unstable!(ffi_pure);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;

fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &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
14 changes: 14 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use rustc_feature::AttributeStability;
use rustc_hir::attrs::ReprAttr;
use rustc_hir::find_attr;

use super::prelude::*;
use crate::session_diagnostics::RustcPubTransparent;

pub(crate) struct RustcAsPtrParser;
impl NoArgsAttributeParser for RustcAsPtrParser {
Expand All @@ -26,6 +29,17 @@ 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) {
// `#[rustc_pub_transparent]` may only be applied to `#[repr(transparent)]` types.
let is_transparent = find_attr!(
cx.parsed_attrs,
Repr { reprs, .. } if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)
);
if !is_transparent {
cx.emit_err(RustcPubTransparent { span: cx.target_span, attr_span });
}
}
}

pub(crate) struct RustcPassByValueParser;
Expand Down
71 changes: 46 additions & 25 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use rustc_span::edition::Edition;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;

use crate::context::{AcceptContext, FinalizeContext};
use crate::context::{AcceptContext, FinalizeCheckContext, FinalizeCheckFn, FinalizeContext};
use crate::parser::ArgParser;
use crate::session_diagnostics::UnusedMultiple;
use crate::target_checking::AllowedTargets;
Expand Down Expand Up @@ -117,6 +117,20 @@ pub(crate) trait AttributeParser: Default + 'static {
/// every single syntax item that could have attributes applied to it.
/// Your accept mappings should determine whether this returns something.
fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind>;

/// If this parser produced an attribute, optionally returns a cross-attribute check
/// to run once *all* attributes on the item have been finalized, together with the
/// span it should be reported at.
///
/// Running after finalization means the check can inspect the fully parsed attributes
/// via [`FinalizeCheckContext::parsed_attrs`], which are not yet all available during
/// [`finalize`](Self::finalize). This is queried right before `finalize` consumes the
/// parser state.
///
/// Defaults to no check.
fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> {
None
}
}

/// Alternative to [`AttributeParser`] that automatically handles state management.
Expand Down Expand Up @@ -148,13 +162,14 @@ pub(crate) trait SingleAttributeParser: 'static {
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind>;

/// Optional cross-attribute validation, run once during finalization after all
/// attributes on the item have been parsed. Unlike [`convert`](Self::convert), this
/// has access to the sibling attributes via [`FinalizeContext::all_attrs`], so it can
/// reject incompatible combinations. `attr_span` is the span of this attribute.
/// Optional cross-attribute validation, run once *after* all attributes on the item
/// have been finalized. Unlike [`convert`](Self::convert), this has access to the
/// sibling attributes via [`FinalizeCheckContext::all_attrs`] and the fully parsed
/// attributes via [`FinalizeCheckContext::parsed_attrs`], so it can reject incompatible
/// combinations. `attr_span` is the span of this attribute.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

/// Use in combination with [`SingleAttributeParser`].
Expand Down Expand Up @@ -185,11 +200,15 @@ impl<T: SingleAttributeParser> AttributeParser for Single<T> {
const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;

fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
let (kind, span) = self.1?;
T::finalize_check(cx, span);
fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
let (kind, _span) = self.1?;
Some(kind)
}

fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> {
let (_, span) = self.1.as_ref()?;
Some((<T as SingleAttributeParser>::finalize_check, *span))
}
}

pub(crate) enum OnDuplicate {
Expand Down Expand Up @@ -269,13 +288,14 @@ pub(crate) trait NoArgsAttributeParser: 'static {
/// Create the [`AttributeKind`] given attribute's [`Span`].
const CREATE: fn(Span) -> AttributeKind;

/// Optional cross-attribute validation, run once during finalization after all
/// attributes on the item have been parsed. Has access to the sibling attributes via
/// [`FinalizeContext::all_attrs`], so it can reject incompatible combinations.
/// Optional cross-attribute validation, run once *after* all attributes on the item
/// have been finalized. Has access to the sibling attributes via
/// [`FinalizeCheckContext::all_attrs`] and the fully parsed attributes via
/// [`FinalizeCheckContext::parsed_attrs`], so it can reject incompatible combinations.
/// `attr_span` is the span of this attribute.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

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

fn finalize_check(cx: &FinalizeContext<'_, '_>, attr_span: Span) {
fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
T::finalize_check(cx, attr_span)
}
}
Expand Down Expand Up @@ -336,13 +356,14 @@ pub(crate) trait CombineAttributeParser: 'static {
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item>;

/// Optional cross-attribute validation, run once during finalization after all
/// attributes on the item have been parsed. Has access to the sibling attributes via
/// [`FinalizeContext::all_attrs`], so it can reject incompatible combinations.
/// Optional cross-attribute validation, run once *after* all attributes on the item
/// have been finalized. Has access to the sibling attributes via
/// [`FinalizeCheckContext::all_attrs`] and the fully parsed attributes via
/// [`FinalizeCheckContext::parsed_attrs`], so it can reject incompatible combinations.
/// `attr_span` is the span of the first attribute that was encountered.
///
/// Defaults to a no-op.
fn finalize_check(_cx: &FinalizeContext<'_, '_>, _attr_span: Span) {}
fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}
}

/// Use in combination with [`CombineAttributeParser`].
Expand Down Expand Up @@ -375,12 +396,12 @@ impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
const ALLOWED_TARGETS: AllowedTargets<'_> = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;

fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
if let Some(first_span) = self.first_span {
T::finalize_check(cx, first_span);
Some(T::CONVERT(self.items, first_span))
} else {
None
}
fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
let first_span = self.first_span?;
Some(T::CONVERT(self.items, first_span))
}

fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> {
Some((<T as CombineAttributeParser>::finalize_check, self.first_span?))
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(super) use crate::attributes::{
};
// contexts
#[doc(hidden)]
pub(super) use crate::context::{AcceptContext, FinalizeContext};
pub(super) use crate::context::{AcceptContext, FinalizeCheckContext, FinalizeContext};
#[doc(hidden)]
pub(super) use crate::parser::*;
// target checking
Expand Down
Loading
Loading