From f98ea3d144208113df2e644a88a650192fad57ad Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 25 Jun 2025 09:44:52 +0200 Subject: [PATCH] Port `#[rustc_layout_scalar_valid_range_start/end]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 6 ++ .../src/encode_cross_crate.rs | 2 + .../rustc_attr_data_structures/src/lib.rs | 10 ++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + .../src/attributes/rustc_internal.rs | 59 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 15 +++++ .../src/session_diagnostics.rs | 4 ++ compiler/rustc_middle/src/ty/context.rs | 30 ++-------- compiler/rustc_passes/messages.ftl | 3 - compiler/rustc_passes/src/check_attr.rs | 27 +++------ compiler/rustc_passes/src/errors.rs | 7 --- ...lid_rustc_layout_scalar_valid_range.stderr | 38 ++++++++---- tests/ui/parser/bad-lit-suffixes.rs | 1 + tests/ui/parser/bad-lit-suffixes.stderr | 12 +++- 14 files changed, 146 insertions(+), 69 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d755afad59fb8..43a79d8456ad6 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -273,6 +273,12 @@ pub enum AttributeKind { /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), + /// Represents `#[rustc_layout_scalar_valid_range_end]`. + RustcLayoutScalarValidRangeEnd(Box, Span), + + /// Represents `#[rustc_layout_scalar_valid_range_start]`. + RustcLayoutScalarValidRangeStart(Box, Span), + /// Represents `#[rustc_skip_during_method_dispatch]`. SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index d4402f4e2e63d..174aa5b85b562 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -36,6 +36,8 @@ impl AttributeKind { NoMangle(..) => No, Optimize(..) => No, PubTransparent(..) => Yes, + RustcLayoutScalarValidRangeEnd(..) => Yes, + RustcLayoutScalarValidRangeStart(..) => Yes, SkipDuringMethodDispatch { .. } => No, TrackCaller(..) => Yes, } diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 86c73f0d9a086..8f8ce575a1830 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -49,6 +49,16 @@ pub trait PrintAttribute { fn print_attribute(&self, p: &mut Printer); } +impl PrintAttribute for u128 { + fn should_render(&self) -> bool { + true + } + + fn print_attribute(&self, p: &mut Printer) { + p.word(self.to_string()) + } +} + impl PrintAttribute for &T { fn should_render(&self) -> bool { T::should_render(self) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index d407669cb410c..a7c1700965351 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -35,6 +35,7 @@ pub(crate) mod lint_helpers; pub(crate) mod loop_match; pub(crate) mod must_use; pub(crate) mod repr; +pub(crate) mod rustc_internal; pub(crate) mod semantics; pub(crate) mod stability; pub(crate) mod traits; diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs new file mode 100644 index 0000000000000..7364a3f20e27f --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -0,0 +1,59 @@ +use rustc_ast::LitKind; +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct RustcLayoutScalarValidRangeStart; + +impl SingleAttributeParser for RustcLayoutScalarValidRangeStart { + const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(List: "start"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + parse_rustc_layout_scalar_valid_range(cx, args) + .map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(n, cx.attr_span)) + } +} + +pub(crate) struct RustcLayoutScalarValidRangeEnd; + +impl SingleAttributeParser for RustcLayoutScalarValidRangeEnd { + const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(List: "end"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + parse_rustc_layout_scalar_valid_range(cx, args) + .map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(n, cx.attr_span)) + } +} + +fn parse_rustc_layout_scalar_valid_range( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, +) -> Option> { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(lit) = single.lit() else { + cx.expected_integer_literal(single.span()); + return None; + }; + let LitKind::Int(num, _ty) = lit.kind else { + cx.expected_integer_literal(single.span()); + return None; + }; + Some(Box::new(num.0)) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 83e3c75dedb4e..659e21c97bc97 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -25,6 +25,9 @@ use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::rustc_internal::{ + RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, +}; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -126,6 +129,8 @@ attribute_parsers!( Single, Single, Single, + Single, + Single, Single, Single, Single, @@ -269,6 +274,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedIntegerLiteral, + }) + } + pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 7cfce5799792a..0a5a42ce32eab 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -503,6 +503,7 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { pub(crate) enum AttributeParseErrorReason { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option }, + ExpectedIntegerLiteral, ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, @@ -543,6 +544,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span_label(self.span, "expected a string literal here"); } } + AttributeParseErrorReason::ExpectedIntegerLiteral => { + diag.span_label(self.span, "expected an integer literal here"); + } AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_label(self.span, "expected a single argument here"); diag.code(E0805); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 457a4f4d5027a..72810491214aa 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -17,6 +17,7 @@ use std::{fmt, iter, mem}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_ast as ast; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -1648,32 +1649,9 @@ impl<'tcx> TyCtxt<'tcx> { /// `rustc_layout_scalar_valid_range` attribute. // FIXME(eddyb) this is an awkward spot for this method, maybe move it? pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound, Bound) { - let get = |name| { - let Some(attr) = self.get_attr(def_id, name) else { - return Bound::Unbounded; - }; - debug!("layout_scalar_valid_range: attr={:?}", attr); - if let Some( - &[ - ast::MetaItemInner::Lit(ast::MetaItemLit { - kind: ast::LitKind::Int(a, _), .. - }), - ], - ) = attr.meta_item_list().as_deref() - { - Bound::Included(a.get()) - } else { - self.dcx().span_delayed_bug( - attr.span(), - "invalid rustc_layout_scalar_valid_range attribute", - ); - Bound::Unbounded - } - }; - ( - get(sym::rustc_layout_scalar_valid_range_start), - get(sym::rustc_layout_scalar_valid_range_end), - ) + let start = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeStart(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded); + let end = find_attr!(self.get_all_attrs(def_id), AttributeKind::RustcLayoutScalarValidRangeEnd(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded); + (start, end) } pub fn lift>>(self, value: T) -> Option { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e2995daadfe56..2a2948f78bddd 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -618,9 +618,6 @@ passes_rustc_force_inline_coro = attribute cannot be applied to a `async`, `gen` or `async gen` function .label = `async`, `gen` or `async gen` function -passes_rustc_layout_scalar_valid_range_arg = - expected exactly one integer literal argument - passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct .label = not a struct diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 491b3699f4c32..b5b297eaf85d2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; -use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; +use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, ast}; use rustc_attr_data_structures::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; @@ -183,6 +183,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { self.check_track_caller(hir_id, *attr_span, attrs, span, target) } + Attribute::Parsed( + AttributeKind::RustcLayoutScalarValidRangeStart(_num, attr_span) + | AttributeKind::RustcLayoutScalarValidRangeEnd(_num, attr_span), + ) => self.check_rustc_layout_scalar_valid_range(*attr_span, span, target), Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -228,10 +232,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &mut doc_aliases, ), [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start, ..] - | [sym::rustc_layout_scalar_valid_range_end, ..] => { - self.check_rustc_layout_scalar_valid_range(attr, span, target) - } [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) @@ -1675,24 +1675,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { + fn check_rustc_layout_scalar_valid_range(&self, attr_span: Span, span: Span, target: Target) { if target != Target::Struct { - self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span(), - span, - }); + self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { attr_span, span }); return; } - - let Some(list) = attr.meta_item_list() else { - return; - }; - - if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { - self.tcx - .dcx() - .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() }); - } } /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3286ccc94f210..107fc17b53672 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -535,13 +535,6 @@ pub(crate) struct RustcLayoutScalarValidRangeNotStruct { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_rustc_layout_scalar_valid_range_arg)] -pub(crate) struct RustcLayoutScalarValidRangeArg { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_rustc_legacy_const_generics_only)] pub(crate) struct RustcLegacyConstGenericsOnly { diff --git a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr index 7879e7358c00a..8b9ad78db3743 100644 --- a/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr +++ b/tests/ui/invalid/invalid_rustc_layout_scalar_valid_range.stderr @@ -1,20 +1,38 @@ -error: expected exactly one integer literal argument +error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:3:1 | LL | #[rustc_layout_scalar_valid_range_start(u32::MAX)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` -error: expected exactly one integer literal argument +error[E0805]: malformed `rustc_layout_scalar_valid_range_end` attribute input --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:6:1 | LL | #[rustc_layout_scalar_valid_range_end(1, 2)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` -error: expected exactly one integer literal argument +error[E0539]: malformed `rustc_layout_scalar_valid_range_end` attribute input --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:9:1 | LL | #[rustc_layout_scalar_valid_range_end(a = "a")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` + +error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input + --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:18:1 + | +LL | #[rustc_layout_scalar_valid_range_start(rustc_layout_scalar_valid_range_start)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------------------------------------^^ + | | | + | | expected an integer literal here + | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error: attribute should be applied to a struct --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:12:1 @@ -27,11 +45,7 @@ LL | | Y = 14, LL | | } | |_- not a struct -error: expected exactly one integer literal argument - --> $DIR/invalid_rustc_layout_scalar_valid_range.rs:18:1 - | -LL | #[rustc_layout_scalar_valid_range_start(rustc_layout_scalar_valid_range_start)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: aborting due to 5 previous errors +Some errors have detailed explanations: E0539, E0805. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/parser/bad-lit-suffixes.rs b/tests/ui/parser/bad-lit-suffixes.rs index 4e8edf4d46eab..13287aabb1d96 100644 --- a/tests/ui/parser/bad-lit-suffixes.rs +++ b/tests/ui/parser/bad-lit-suffixes.rs @@ -41,4 +41,5 @@ extern "C" {} #[rustc_layout_scalar_valid_range_start(0suffix)] //~^ ERROR invalid suffix `suffix` for number literal +//~| ERROR malformed `rustc_layout_scalar_valid_range_start` attribute input struct S; diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 416143e496aff..295e3112ec0a8 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -150,5 +150,15 @@ LL | 1.0e10suffix; | = help: valid suffixes are `f32` and `f64` -error: aborting due to 20 previous errors; 2 warnings emitted +error[E0805]: malformed `rustc_layout_scalar_valid_range_start` attribute input + --> $DIR/bad-lit-suffixes.rs:42:1 + | +LL | #[rustc_layout_scalar_valid_range_start(0suffix)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^ + | | | + | | expected a single argument here + | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` + +error: aborting due to 21 previous errors; 2 warnings emitted +For more information about this error, try `rustc --explain E0805`.