Skip to content

Commit 2c99fd0

Browse files
Allow Early stage to emit errors
1 parent 5363fcf commit 2c99fd0

File tree

5 files changed

+93
-18
lines changed

5 files changed

+93
-18
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use std::sync::Arc;
4242

4343
use rustc_ast::node_id::NodeMap;
4444
use rustc_ast::{self as ast, *};
45-
use rustc_attr_parsing::{AttributeParser, OmitDoc};
45+
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
4646
use rustc_data_structures::fingerprint::Fingerprint;
4747
use rustc_data_structures::sorted_map::SortedMap;
4848
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -192,7 +192,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
192192
// interact with `gen`/`async gen` blocks
193193
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
194194

195-
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
195+
attribute_parser: AttributeParser::new(
196+
tcx.sess,
197+
tcx.features(),
198+
registered_tools,
199+
Late,
200+
),
196201
delayed_lints: Vec::new(),
197202
}
198203
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::cell::RefCell;
22
use std::collections::BTreeMap;
3-
use std::marker::PhantomData;
43
use std::ops::{Deref, DerefMut};
54
use std::sync::LazyLock;
65

@@ -180,7 +179,11 @@ pub trait Stage: Sized + 'static + Sealed {
180179

181180
fn parsers() -> &'static group_type!(Self);
182181

183-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
182+
fn emit_err<'sess>(
183+
&self,
184+
sess: &'sess Session,
185+
diag: impl for<'x> Diagnostic<'x>,
186+
) -> ErrorGuaranteed;
184187
}
185188

186189
// allow because it's a sealed trait
@@ -192,8 +195,16 @@ impl Stage for Early {
192195
fn parsers() -> &'static group_type!(Self) {
193196
&early::ATTRIBUTE_PARSERS
194197
}
195-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
196-
sess.dcx().create_err(diag).delay_as_bug()
198+
fn emit_err<'sess>(
199+
&self,
200+
sess: &'sess Session,
201+
diag: impl for<'x> Diagnostic<'x>,
202+
) -> ErrorGuaranteed {
203+
if self.emit_errors {
204+
sess.dcx().emit_err(diag)
205+
} else {
206+
sess.dcx().create_err(diag).delay_as_bug()
207+
}
197208
}
198209
}
199210

@@ -206,20 +217,29 @@ impl Stage for Late {
206217
fn parsers() -> &'static group_type!(Self) {
207218
&late::ATTRIBUTE_PARSERS
208219
}
209-
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
220+
fn emit_err<'sess>(
221+
&self,
222+
tcx: &'sess Session,
223+
diag: impl for<'x> Diagnostic<'x>,
224+
) -> ErrorGuaranteed {
210225
tcx.dcx().emit_err(diag)
211226
}
212227
}
213228

214229
/// used when parsing attributes for miscellaneous things *before* ast lowering
215-
pub struct Early;
230+
pub struct Early {
231+
/// Whether to emit errors or delay them as a bug
232+
/// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
233+
/// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
234+
pub emit_errors: bool,
235+
}
216236
/// used when parsing attributes during ast lowering
217237
pub struct Late;
218238

219239
/// Context given to every attribute parser when accepting
220240
///
221241
/// Gives [`AttributeParser`]s enough information to create errors, for example.
222-
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
242+
pub struct AcceptContext<'f, 'sess, S: Stage> {
223243
pub(crate) shared: SharedContext<'f, 'sess, S>,
224244
/// The span of the attribute currently being parsed
225245
pub(crate) attr_span: Span,
@@ -235,7 +255,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
235255

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

241261
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -450,7 +470,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
450470
///
451471
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
452472
/// errors, for example.
453-
pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
473+
pub struct SharedContext<'p, 'sess, S: Stage> {
454474
/// The parse context, gives access to the session and the
455475
/// diagnostics context.
456476
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
@@ -518,7 +538,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
518538
pub(crate) tools: Vec<Symbol>,
519539
features: Option<&'sess Features>,
520540
sess: &'sess Session,
521-
stage: PhantomData<S>,
541+
stage: S,
522542

523543
/// *Only* parse attributes with this symbol.
524544
///
@@ -547,13 +567,14 @@ impl<'sess> AttributeParser<'sess, Early> {
547567
sym: Symbol,
548568
target_span: Span,
549569
target_node_id: NodeId,
570+
features: Option<&'sess Features>,
550571
) -> Option<Attribute> {
551572
let mut p = Self {
552-
features: None,
573+
features,
553574
tools: Vec::new(),
554575
parse_only: Some(sym),
555576
sess,
556-
stage: PhantomData,
577+
stage: Early { emit_errors: false },
557578
};
558579
let mut parsed = p.parse_attribute_list(
559580
attrs,
@@ -569,11 +590,55 @@ impl<'sess> AttributeParser<'sess, Early> {
569590

570591
parsed.pop()
571592
}
593+
594+
pub fn parse_single<T>(
595+
sess: &'sess Session,
596+
attr: &ast::Attribute,
597+
target_span: Span,
598+
target_node_id: NodeId,
599+
features: Option<&'sess Features>,
600+
emit_errors: bool,
601+
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
602+
template: &AttributeTemplate,
603+
) -> T {
604+
let mut parser = Self {
605+
features,
606+
tools: Vec::new(),
607+
parse_only: None,
608+
sess,
609+
stage: Early { emit_errors },
610+
};
611+
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
612+
panic!("parse_single called on a doc attr")
613+
};
614+
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
615+
let path = meta_parser.path();
616+
let args = meta_parser.args();
617+
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
618+
shared: SharedContext {
619+
cx: &mut parser,
620+
target_span,
621+
target_id: target_node_id,
622+
emit_lint: &mut |_lint| {
623+
panic!("can't emit lints here for now (nothing uses this atm)");
624+
},
625+
},
626+
attr_span: attr.span,
627+
template,
628+
attr_path: path.get_attribute_path(),
629+
};
630+
parse_fn(&mut cx, args)
631+
}
572632
}
573633

574634
impl<'sess, S: Stage> AttributeParser<'sess, S> {
575-
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
576-
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
635+
pub fn new(
636+
sess: &'sess Session,
637+
features: &'sess Features,
638+
tools: Vec<Symbol>,
639+
stage: S,
640+
) -> Self {
641+
Self { features: Some(features), tools, parse_only: None, sess, stage }
577642
}
578643

579644
pub(crate) fn sess(&self) -> &'sess Session {
@@ -584,6 +649,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
584649
self.features.expect("features not available at this point in the compiler")
585650
}
586651

652+
pub(crate) fn features_option(&self) -> Option<&'sess Features> {
653+
self.features
654+
}
655+
587656
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
588657
self.sess().dcx()
589658
}

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
484484
match item {
485485
Annotatable::Item(item) => {
486486
let is_packed = matches!(
487-
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
487+
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, None),
488488
Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
489489
);
490490

compiler/rustc_lint/src/nonstandard_style.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ impl NonCamelCaseTypes {
167167
impl EarlyLintPass for NonCamelCaseTypes {
168168
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
169169
let has_repr_c = matches!(
170-
AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id),
170+
AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, None),
171171
Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC)
172172
);
173173

compiler/rustc_resolve/src/def_collector.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
132132
&self.resolver.tcx.sess,
133133
self.resolver.tcx.features(),
134134
Vec::new(),
135+
Early { emit_errors: false },
135136
);
136137
let attrs = parser.parse_attribute_list(
137138
&i.attrs,

0 commit comments

Comments
 (0)