Skip to content
Open
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
23 changes: 22 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,13 @@ use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, *};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
use rustc_hir::attrs::AttrResolution;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
Expand Down Expand Up @@ -155,6 +156,7 @@ struct LoweringContext<'a, 'hir, R> {
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
let attr_res_map = resolver.all_attr_resolutions();
Self {
tcx,
resolver,
Expand Down Expand Up @@ -209,6 +211,7 @@ impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
tcx.sess,
tcx.features(),
registered_tools,
attr_res_map,
Late,
),
delayed_lints: Vec::new(),
Expand Down Expand Up @@ -239,6 +242,7 @@ impl SpanLowerer {
struct ResolverDelayedAstLowering<'a, 'tcx> {
node_id_to_def_id: NodeMap<LocalDefId>,
partial_res_map: NodeMap<PartialRes>,
attr_res_map: FxIndexMap<rustc_span::AttrId, Vec<AttrResolution<ast::NodeId>>>,
next_node_id: NodeId,
base: &'a ResolverAstLowering<'tcx>,
}
Expand All @@ -253,6 +257,16 @@ impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, '
self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
}

fn all_attr_resolutions(
&self,
) -> FxIndexMap<rustc_span::AttrId, Vec<AttrResolution<ast::NodeId>>> {
let mut map = self.base.all_attr_resolutions();
for (attr_id, resolutions) in &self.attr_res_map {
map.entry(*attr_id).or_default().extend(resolutions.iter().copied());
}
map
}

fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
self.base.get_import_res(id)
}
Expand Down Expand Up @@ -345,6 +359,12 @@ impl<'tcx> ResolverAstLowering<'tcx> {
self.partial_res_map.get(&id).copied()
}

fn all_attr_resolutions(
&self,
) -> FxIndexMap<rustc_span::AttrId, Vec<AttrResolution<ast::NodeId>>> {
self.attr_res_map.clone()
}

/// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
self.import_res_map.get(&id).copied().unwrap_or_default()
Expand Down Expand Up @@ -663,6 +683,7 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let mut resolver = ResolverDelayedAstLowering {
next_node_id: resolver.next_node_id,
partial_res_map: Default::default(),
attr_res_map: Default::default(),
node_id_to_def_id: Default::default(),
base: resolver,
};
Expand Down
148 changes: 104 additions & 44 deletions compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use rustc_abi::{Align, Size};
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
use rustc_hir::attrs::{IntType, ReprAttr};
use rustc_hir::attrs::{AttrIntValue, AttrResolutionKind, AttrResolved, IntType, ReprAttr};
use rustc_hir::def::{DefKind, Res};
use rustc_session::parse::feature_err;

use super::prelude::*;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
use crate::ShouldEmit;
use crate::session_diagnostics::{
self, AttrConstGenericNotSupported, AttrConstPathNotConst, IncorrectReprFormatGenericCause,
};

/// Parse #[repr(...)] forms.
///
Expand Down Expand Up @@ -100,7 +105,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
}
}

fn parse_repr<S: Stage>(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -> Option<ReprAttr> {
fn parse_repr<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
param: &MetaItemParser,
) -> Option<ReprAttr> {
use ReprAttr::*;

// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
Expand All @@ -122,7 +130,7 @@ fn parse_repr<S: Stage>(cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser) -
parse_repr_align(cx, l, param.span(), AlignKind::Align)
}

(Some(sym::packed), ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
(Some(sym::packed), ArgParser::NoArgs) => Some(ReprPacked(AttrIntValue::Lit(1))),
(Some(sym::packed), ArgParser::List(l)) => {
parse_repr_align(cx, l, param.span(), AlignKind::Packed)
}
Expand Down Expand Up @@ -189,8 +197,13 @@ enum AlignKind {
Align,
}

enum AlignmentParseError {
Message(String),
AlreadyErrored,
}

fn parse_repr_align<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
cx: &mut AcceptContext<'_, '_, S>,
list: &MetaItemListParser,
param_span: Span,
align_kind: AlignKind,
Expand All @@ -214,31 +227,21 @@ fn parse_repr_align<S: Stage>(
return None;
};

let Some(lit) = align.lit() else {
match parse_alignment_or_const_path(
cx,
align,
match align_kind {
Packed => {
cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
span: align.span(),
});
}
Align => {
cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
span: align.span(),
});
}
}

return None;
};

match parse_alignment(&lit.kind, cx) {
Ok(literal) => Some(match align_kind {
AlignKind::Packed => ReprAttr::ReprPacked(literal),
AlignKind::Align => ReprAttr::ReprAlign(literal),
Packed => "repr(packed)",
Align => "repr(align)",
},
) {
Ok(value) => Some(match align_kind {
AlignKind::Packed => ReprAttr::ReprPacked(value),
AlignKind::Align => ReprAttr::ReprAlign(value),
}),
Err(message) => {
Err(AlignmentParseError::Message(message)) => {
cx.emit_err(session_diagnostics::InvalidReprGeneric {
span: lit.span,
span: align.span(),
repr_arg: match align_kind {
Packed => "packed".to_string(),
Align => "align".to_string(),
Expand All @@ -247,6 +250,7 @@ fn parse_repr_align<S: Stage>(
});
None
}
Err(AlignmentParseError::AlreadyErrored) => None,
}
}

Expand Down Expand Up @@ -281,9 +285,74 @@ fn parse_alignment<S: Stage>(
Ok(align)
}

fn parse_alignment_or_const_path<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
arg: &MetaItemOrLitParser,
attr_name: &'static str,
) -> Result<AttrIntValue, AlignmentParseError> {
if let Some(lit) = arg.lit() {
return parse_alignment(&lit.kind, cx)
.map(|align| AttrIntValue::Lit(u128::from(align.bytes())))
.map_err(AlignmentParseError::Message);
}

let Some(meta) = arg.meta_item() else {
return Err(AlignmentParseError::Message("not an unsuffixed integer".to_string()));
};

if !matches!(meta.args(), ArgParser::NoArgs) {
return Err(AlignmentParseError::Message("not an unsuffixed integer".to_string()));
}

let path_span = meta.path().span();
let feature_enabled = cx.features_option().is_some_and(|features| features.const_attr_paths())
|| path_span.allows_unstable(sym::const_attr_paths);

if !feature_enabled {
if matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
return Ok(AttrIntValue::Lit(1));
}

feature_err(
cx.sess(),
sym::const_attr_paths,
meta.span(),
"const item paths in builtin attributes are experimental",
)
.emit();
return Err(AlignmentParseError::AlreadyErrored);
}

cx.record_attr_resolution_request(AttrResolutionKind::Const, meta.path().0.clone());

let Some(resolution) = cx.attr_resolution(AttrResolutionKind::Const, path_span) else {
// `parse_limited(sym::repr)` runs before lowering for callers that only care whether
// `repr(packed(...))` exists at all.
if matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
return Ok(AttrIntValue::Lit(1));
}
return Err(AlignmentParseError::Message("not an unsuffixed integer".to_string()));
};

match resolution {
AttrResolved::Resolved(Res::Def(DefKind::Const { .. }, def_id)) => {
Ok(AttrIntValue::Const { def_id, span: path_span })
}
AttrResolved::Resolved(Res::Def(DefKind::ConstParam, _)) => {
cx.emit_err(AttrConstGenericNotSupported { span: path_span, attr_name });
Err(AlignmentParseError::AlreadyErrored)
}
AttrResolved::Resolved(res) => {
cx.emit_err(AttrConstPathNotConst { span: path_span, attr_name, thing: res.descr() });
Err(AlignmentParseError::AlreadyErrored)
}
AttrResolved::Error => Err(AlignmentParseError::AlreadyErrored),
}
}

/// Parse #[align(N)].
#[derive(Default)]
pub(crate) struct RustcAlignParser(Option<(Align, Span)>);
pub(crate) struct RustcAlignParser(ThinVec<(AttrIntValue, Span)>);

impl RustcAlignParser {
const PATH: &[Symbol] = &[sym::rustc_align];
Expand All @@ -301,22 +370,15 @@ impl RustcAlignParser {
return;
};

let Some(lit) = align.lit() else {
cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
span: align.span(),
});

return;
};

match parse_alignment(&lit.kind, cx) {
Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))),
Err(message) => {
match parse_alignment_or_const_path(cx, align, "rustc_align") {
Ok(literal) => self.0.push((literal, cx.attr_span)),
Err(AlignmentParseError::Message(message)) => {
cx.emit_err(session_diagnostics::InvalidAlignmentValue {
span: lit.span,
span: align.span(),
error_part: message,
});
}
Err(AlignmentParseError::AlreadyErrored) => {}
}
}
}
Expand All @@ -335,8 +397,7 @@ impl<S: Stage> AttributeParser<S> for RustcAlignParser {
]);

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (align, span) = self.0?;
Some(AttributeKind::RustcAlign { align, span })
(!self.0.is_empty()).then_some(AttributeKind::RustcAlign { aligns: self.0 })
}
}

Expand All @@ -358,7 +419,6 @@ impl<S: Stage> AttributeParser<S> for RustcAlignStaticParser {
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (align, span) = self.0.0?;
Some(AttributeKind::RustcAlign { align, span })
(!self.0.0.is_empty()).then_some(AttributeKind::RustcAlign { aligns: self.0.0 })
}
}
26 changes: 24 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use private::Sealed;
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::attrs::{AttrResolutionKind, AttributeKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, HirId};
use rustc_parse::parser::Recovery;
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use rustc_span::{AttrId, ErrorGuaranteed, Span, Symbol};

use crate::AttributeParser;
// Glob imports to avoid big, bitrotty import lists
Expand Down Expand Up @@ -414,6 +414,7 @@ pub struct Late;
/// Gives [`AttributeParser`]s enough information to create errors, for example.
pub struct AcceptContext<'f, 'sess, S: Stage> {
pub(crate) shared: SharedContext<'f, 'sess, S>,
pub(crate) attr_id: Option<AttrId>,

/// The outer span of the attribute currently being parsed
///
Expand Down Expand Up @@ -498,6 +499,27 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> {
AttributeDiagnosticContext { ctx: self, custom_suggestions: Vec::new() }
}

pub(crate) fn attr_resolution(
&self,
kind: AttrResolutionKind,
path_span: Span,
) -> Option<rustc_hir::attrs::AttrResolved<NodeId>> {
self.attr_id.and_then(|attr_id| self.shared.cx.attr_resolution(attr_id, kind, path_span))
}

pub(crate) fn record_attr_resolution_request(
&mut self,
kind: AttrResolutionKind,
path: rustc_ast::Path,
) {
if let Some(attr_id) = self.attr_id {
self.shared.cx.record_attr_resolution_request(
attr_id,
crate::interface::AttrResolutionRequest { kind, path },
);
}
}
}

impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
Expand Down
Loading
Loading