Skip to content

Commit 38dd6f5

Browse files
Allow Early stage to emit errors
1 parent a14baf1 commit 38dd6f5

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

@@ -202,7 +201,11 @@ pub trait Stage: Sized + 'static + Sealed {
202201

203202
fn parsers() -> &'static group_type!(Self);
204203

205-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
204+
fn emit_err<'sess>(
205+
&self,
206+
sess: &'sess Session,
207+
diag: impl for<'x> Diagnostic<'x>,
208+
) -> ErrorGuaranteed;
206209
}
207210

208211
// allow because it's a sealed trait
@@ -214,8 +217,16 @@ impl Stage for Early {
214217
fn parsers() -> &'static group_type!(Self) {
215218
&early::ATTRIBUTE_PARSERS
216219
}
217-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
218-
sess.dcx().create_err(diag).delay_as_bug()
220+
fn emit_err<'sess>(
221+
&self,
222+
sess: &'sess Session,
223+
diag: impl for<'x> Diagnostic<'x>,
224+
) -> ErrorGuaranteed {
225+
if self.emit_errors {
226+
sess.dcx().emit_err(diag)
227+
} else {
228+
sess.dcx().create_err(diag).delay_as_bug()
229+
}
219230
}
220231
}
221232

@@ -228,20 +239,29 @@ impl Stage for Late {
228239
fn parsers() -> &'static group_type!(Self) {
229240
&late::ATTRIBUTE_PARSERS
230241
}
231-
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
242+
fn emit_err<'sess>(
243+
&self,
244+
tcx: &'sess Session,
245+
diag: impl for<'x> Diagnostic<'x>,
246+
) -> ErrorGuaranteed {
232247
tcx.dcx().emit_err(diag)
233248
}
234249
}
235250

236251
/// used when parsing attributes for miscellaneous things *before* ast lowering
237-
pub struct Early;
252+
pub struct Early {
253+
/// Whether to emit errors or delay them as a bug
254+
/// For most attributes, the attribute will be parsed again in the `Late` stage and in this case the errors should be delayed
255+
/// But for some, such as `cfg`, the attribute will be removed before the `Late` stage so errors must be emitted
256+
pub emit_errors: bool,
257+
}
238258
/// used when parsing attributes during ast lowering
239259
pub struct Late;
240260

241261
/// Context given to every attribute parser when accepting
242262
///
243263
/// Gives [`AttributeParser`]s enough information to create errors, for example.
244-
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
264+
pub struct AcceptContext<'f, 'sess, S: Stage> {
245265
pub(crate) shared: SharedContext<'f, 'sess, S>,
246266
/// The span of the attribute currently being parsed
247267
pub(crate) attr_span: Span,
@@ -257,7 +277,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
257277

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

263283
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -472,7 +492,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
472492
///
473493
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
474494
/// errors, for example.
475-
pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
495+
pub struct SharedContext<'p, 'sess, S: Stage> {
476496
/// The parse context, gives access to the session and the
477497
/// diagnostics context.
478498
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
@@ -540,7 +560,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
540560
pub(crate) tools: Vec<Symbol>,
541561
features: Option<&'sess Features>,
542562
sess: &'sess Session,
543-
stage: PhantomData<S>,
563+
stage: S,
544564

545565
/// *Only* parse attributes with this symbol.
546566
///
@@ -569,13 +589,14 @@ impl<'sess> AttributeParser<'sess, Early> {
569589
sym: Symbol,
570590
target_span: Span,
571591
target_node_id: NodeId,
592+
features: Option<&'sess Features>,
572593
) -> Option<Attribute> {
573594
let mut p = Self {
574-
features: None,
595+
features,
575596
tools: Vec::new(),
576597
parse_only: Some(sym),
577598
sess,
578-
stage: PhantomData,
599+
stage: Early { emit_errors: false },
579600
};
580601
let mut parsed = p.parse_attribute_list(
581602
attrs,
@@ -591,11 +612,55 @@ impl<'sess> AttributeParser<'sess, Early> {
591612

592613
parsed.pop()
593614
}
615+
616+
pub fn parse_single<T>(
617+
sess: &'sess Session,
618+
attr: &ast::Attribute,
619+
target_span: Span,
620+
target_node_id: NodeId,
621+
features: Option<&'sess Features>,
622+
emit_errors: bool,
623+
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
624+
template: &AttributeTemplate,
625+
) -> T {
626+
let mut parser = Self {
627+
features,
628+
tools: Vec::new(),
629+
parse_only: None,
630+
sess,
631+
stage: Early { emit_errors },
632+
};
633+
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
634+
panic!("parse_single called on a doc attr")
635+
};
636+
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
637+
let path = meta_parser.path();
638+
let args = meta_parser.args();
639+
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
640+
shared: SharedContext {
641+
cx: &mut parser,
642+
target_span,
643+
target_id: target_node_id,
644+
emit_lint: &mut |_lint| {
645+
panic!("can't emit lints here for now (nothing uses this atm)");
646+
},
647+
},
648+
attr_span: attr.span,
649+
template,
650+
attr_path: path.get_attribute_path(),
651+
};
652+
parse_fn(&mut cx, args)
653+
}
594654
}
595655

596656
impl<'sess, S: Stage> AttributeParser<'sess, S> {
597-
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
598-
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
657+
pub fn new(
658+
sess: &'sess Session,
659+
features: &'sess Features,
660+
tools: Vec<Symbol>,
661+
stage: S,
662+
) -> Self {
663+
Self { features: Some(features), tools, parse_only: None, sess, stage }
599664
}
600665

601666
pub(crate) fn sess(&self) -> &'sess Session {
@@ -606,6 +671,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
606671
self.features.expect("features not available at this point in the compiler")
607672
}
608673

674+
pub(crate) fn features_option(&self) -> Option<&'sess Features> {
675+
self.features
676+
}
677+
609678
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
610679
self.sess().dcx()
611680
}

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)