Skip to content
Draft
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
7 changes: 7 additions & 0 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ impl Attribute {
}
}

pub fn get_mut_normal_item(&mut self) -> &mut AttrItem {
match &mut self.kind {
AttrKind::Normal(normal) => &mut normal.item,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}

pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => normal.item,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use std::sync::Arc;

use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, *};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc, ShouldEmit};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
Expand Down Expand Up @@ -208,6 +208,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tcx.features(),
registered_tools,
Late,
ShouldEmit::ErrorsAndLints,
),
delayed_lints: Vec::new(),
}
Expand Down
16 changes: 10 additions & 6 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn parse_cfg_entry_version<S: Stage>(
list: &MetaItemListParser,
meta_span: Span,
) -> Result<CfgEntry, ErrorGuaranteed> {
try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
try_gate_cfg(sym::version, meta_span, cx);
let Some(version) = list.single() else {
return Err(
cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span })
Expand Down Expand Up @@ -135,7 +135,8 @@ fn parse_cfg_entry_target<S: Stage>(
list: &MetaItemListParser,
meta_span: Span,
) -> Result<CfgEntry, ErrorGuaranteed> {
if let Some(features) = cx.features_option()
if let ShouldEmit::ErrorsAndLints = cx.should_emit
&& let Some(features) = cx.features_option()
&& !features.cfg_target_compact()
{
feature_err(
Expand Down Expand Up @@ -180,7 +181,7 @@ pub(crate) fn parse_name_value<S: Stage>(
span: Span,
cx: &mut AcceptContext<'_, '_, S>,
) -> Result<CfgEntry, ErrorGuaranteed> {
try_gate_cfg(name, span, cx.sess(), cx.features_option());
try_gate_cfg(name, span, cx);

let value = match value {
None => None,
Expand Down Expand Up @@ -413,10 +414,13 @@ fn parse_cfg_attr_internal<'a>(
Ok((cfg_predicate, expanded_attrs))
}

fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) {
fn try_gate_cfg<S: Stage>(name: Symbol, span: Span, cx: &mut AcceptContext<'_, '_, S>) {
if let ShouldEmit::Nothing = cx.should_emit {
return;
}
let gate = find_gated_cfg(|sym| sym == name);
if let (Some(feats), Some(gated_cfg)) = (features, gate) {
gate_cfg(gated_cfg, span, sess, feats);
if let (Some(feats), Some(gated_cfg)) = (cx.features, gate) {
gate_cfg(gated_cfg, span, cx.sess, feats);
}
}

Expand Down
50 changes: 50 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg_trace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use rustc_feature::AttributeTemplate;
use rustc_hir::attrs::{AttributeKind, CfgEntry};
use rustc_span::{Span, Symbol, sym};

use crate::attributes::{CombineAttributeParser, ConvertFn};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
use crate::{CFG_TEMPLATE, parse_cfg_entry};

pub(crate) struct CfgTraceParser;

impl<S: Stage> CombineAttributeParser<S> for CfgTraceParser {
const PATH: &[Symbol] = &[sym::cfg_trace];
type Item = (CfgEntry, Span);
const CONVERT: ConvertFn<Self::Item> = |c, _| AttributeKind::CfgTrace(c);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const TEMPLATE: AttributeTemplate = CFG_TEMPLATE;

fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let Some(list) = args.list() else {
return None;
};
let Some(entry) = list.single() else {
return None;
};

Some((parse_cfg_entry(cx, entry).ok()?, cx.attr_span))
}
}

pub(crate) struct CfgAttrTraceParser;

impl<S: Stage> CombineAttributeParser<S> for CfgAttrTraceParser {
const PATH: &[Symbol] = &[sym::cfg_attr_trace];
type Item = ();
const CONVERT: ConvertFn<Self::Item> = AttributeKind::CfgAttrTrace;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const TEMPLATE: AttributeTemplate = CFG_TEMPLATE;

fn extend(
_cx: &mut AcceptContext<'_, '_, S>,
_args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
Some(())
}
}
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub(crate) mod allow_unstable;
pub(crate) mod body;
pub(crate) mod cfg;
pub(crate) mod cfg_select;
pub(crate) mod cfg_trace;
pub(crate) mod codegen_attrs;
pub(crate) mod confusables;
pub(crate) mod crate_level;
Expand Down
50 changes: 7 additions & 43 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ use std::sync::LazyLock;

use private::Sealed;
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_errors::{Diag, Level};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{ErrorGuaranteed, Span, Symbol};

Expand All @@ -19,6 +18,7 @@ use crate::attributes::allow_unstable::{
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
};
use crate::attributes::body::CoroutineParser;
use crate::attributes::cfg_trace::{CfgAttrTraceParser, CfgTraceParser};
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser,
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
Expand Down Expand Up @@ -175,6 +175,8 @@ attribute_parsers!(
// tidy-alphabetical-start
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<CfgAttrTraceParser>,
Combine<CfgTraceParser>,
Combine<DebuggerViualizerParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Expand Down Expand Up @@ -279,14 +281,6 @@ pub trait Stage: Sized + 'static + Sealed {

fn parsers() -> &'static GroupType<Self>;

fn emit_err<'sess>(
&self,
sess: &'sess Session,
diag: impl for<'x> Diagnostic<'x>,
) -> ErrorGuaranteed;

fn should_emit(&self) -> ShouldEmit;

fn id_is_crate_root(id: Self::Id) -> bool;
}

Expand All @@ -298,17 +292,6 @@ impl Stage for Early {
fn parsers() -> &'static GroupType<Self> {
&early::ATTRIBUTE_PARSERS
}
fn emit_err<'sess>(
&self,
sess: &'sess Session,
diag: impl for<'x> Diagnostic<'x>,
) -> ErrorGuaranteed {
self.should_emit().emit_err(sess.dcx().create_err(diag))
}

fn should_emit(&self) -> ShouldEmit {
self.emit_errors
}

fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_NODE_ID
Expand All @@ -323,30 +306,15 @@ impl Stage for Late {
fn parsers() -> &'static GroupType<Self> {
&late::ATTRIBUTE_PARSERS
}
fn emit_err<'sess>(
&self,
tcx: &'sess Session,
diag: impl for<'x> Diagnostic<'x>,
) -> ErrorGuaranteed {
tcx.dcx().emit_err(diag)
}

fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints
}

fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_HIR_ID
}
}

/// used when parsing attributes for miscellaneous things *before* ast lowering
pub struct Early {
/// Whether to emit errors or delay them as a bug
/// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
/// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
pub emit_errors: ShouldEmit,
}
pub struct Early;

/// used when parsing attributes during ast lowering
pub struct Late;

Expand Down Expand Up @@ -383,16 +351,12 @@ pub struct AcceptContext<'f, 'sess, S: Stage> {
}

impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
self.stage.emit_err(&self.sess, diag)
}

/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
if !matches!(
self.stage.should_emit(),
self.should_emit,
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
Expand Down
38 changes: 25 additions & 13 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use std::convert::identity;
use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrStyle, NodeId, Safety};
use rustc_errors::DiagCtxtHandle;
use rustc_errors::{DiagCtxtHandle, Diagnostic};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLint;
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};

use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
use crate::parser::{ArgParser, PathParser, RefPathParser};
Expand All @@ -23,7 +23,8 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
pub(crate) tools: Vec<Symbol>,
pub(crate) features: Option<&'sess Features>,
pub(crate) sess: &'sess Session,
pub(crate) stage: S,
pub(crate) _stage: S,
pub(crate) should_emit: ShouldEmit,

/// *Only* parse attributes with this symbol.
///
Expand Down Expand Up @@ -105,10 +106,10 @@ impl<'sess> AttributeParser<'sess, Early> {
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
should_emit: ShouldEmit,
) -> Vec<Attribute> {
let mut p =
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
Self { features, tools: Vec::new(), parse_only, sess, _stage: Early, should_emit };
p.parse_attribute_list(
attrs,
target_span,
Expand Down Expand Up @@ -179,7 +180,7 @@ impl<'sess> AttributeParser<'sess, Early> {
target_span: Span,
target_node_id: NodeId,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
should_emit: ShouldEmit,
args: &I,
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> T,
template: &AttributeTemplate,
Expand All @@ -189,7 +190,8 @@ impl<'sess> AttributeParser<'sess, Early> {
tools: Vec::new(),
parse_only: None,
sess,
stage: Early { emit_errors },
_stage: Early,
should_emit,
};
let mut emit_lint = |lint: AttributeLint<NodeId>| {
sess.psess.buffer_lint(
Expand Down Expand Up @@ -232,8 +234,9 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
features: &'sess Features,
tools: Vec<Symbol>,
stage: S,
should_emit: ShouldEmit,
) -> Self {
Self { features: Some(features), tools, parse_only: None, sess, stage }
Self { features: Some(features), tools, parse_only: None, sess, _stage: stage, should_emit }
}

pub(crate) fn sess(&self) -> &'sess Session {
Expand All @@ -252,6 +255,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
self.sess().dcx()
}

pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
self.should_emit.emit_err(self.dcx().create_err(diag))
}

/// Parse a list of attributes.
///
/// `target_span` is the span of the thing this list of attributes is applied to,
Expand All @@ -263,14 +270,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
target_id: S::Id,
target: Target,
omit_doc: OmitDoc,

lower_span: impl Copy + Fn(Span) -> Span,
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
) -> Vec<Attribute> {
let mut attributes = Vec::new();
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
let old_should_emit = self.should_emit;

for attr in attrs {
self.should_emit = old_should_emit; //FIXME ugly solution

// If we're only looking for a single attribute, skip all the ones we don't care about.
if let Some(expected) = self.parse_only {
if !attr.has_name(expected) {
Expand Down Expand Up @@ -305,6 +314,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attr_paths.push(PathParser(&n.item.path));
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);

// Don't emit anything for trace attributes
if attr.has_any_name(&[sym::cfg_trace, sym::cfg_attr_trace]) {
self.should_emit = ShouldEmit::Nothing;
}

self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
Expand All @@ -321,7 +335,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
&n.item.args,
&parts,
&self.sess.psess,
self.stage.should_emit(),
self.should_emit,
) else {
continue;
};
Expand Down Expand Up @@ -374,9 +388,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
};

(accept.accept_fn)(&mut cx, &args);
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
Self::check_target(&accept.allowed_targets, target, &mut cx);
}
Self::check_target(&accept.allowed_targets, target, &mut cx);
}
} else {
// If we're here, we must be compiling a tool attribute... Or someone
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ impl ArgParser {
}

if args.delim != Delimiter::Parenthesis {
psess.dcx().emit_err(MetaBadDelim {
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
span: args.dspan.entire(),
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
});
}));
return None;
}

Expand Down
Loading
Loading