Skip to content

Commit 2ed85b4

Browse files
Allow Early stage to emit errors
1 parent ac614ee commit 2ed85b4

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

@@ -200,7 +199,11 @@ pub trait Stage: Sized + 'static + Sealed {
200199

201200
fn parsers() -> &'static group_type!(Self);
202201

203-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
202+
fn emit_err<'sess>(
203+
&self,
204+
sess: &'sess Session,
205+
diag: impl for<'x> Diagnostic<'x>,
206+
) -> ErrorGuaranteed;
204207
}
205208

206209
// allow because it's a sealed trait
@@ -212,8 +215,16 @@ impl Stage for Early {
212215
fn parsers() -> &'static group_type!(Self) {
213216
&early::ATTRIBUTE_PARSERS
214217
}
215-
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
216-
sess.dcx().create_err(diag).delay_as_bug()
218+
fn emit_err<'sess>(
219+
&self,
220+
sess: &'sess Session,
221+
diag: impl for<'x> Diagnostic<'x>,
222+
) -> ErrorGuaranteed {
223+
if self.emit_errors {
224+
sess.dcx().emit_err(diag)
225+
} else {
226+
sess.dcx().create_err(diag).delay_as_bug()
227+
}
217228
}
218229
}
219230

@@ -226,20 +237,29 @@ impl Stage for Late {
226237
fn parsers() -> &'static group_type!(Self) {
227238
&late::ATTRIBUTE_PARSERS
228239
}
229-
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
240+
fn emit_err<'sess>(
241+
&self,
242+
tcx: &'sess Session,
243+
diag: impl for<'x> Diagnostic<'x>,
244+
) -> ErrorGuaranteed {
230245
tcx.dcx().emit_err(diag)
231246
}
232247
}
233248

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

239259
/// Context given to every attribute parser when accepting
240260
///
241261
/// Gives [`AttributeParser`]s enough information to create errors, for example.
242-
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
262+
pub struct AcceptContext<'f, 'sess, S: Stage> {
243263
pub(crate) shared: SharedContext<'f, 'sess, S>,
244264
/// The span of the attribute currently being parsed
245265
pub(crate) attr_span: Span,
@@ -255,7 +275,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
255275

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

261281
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
@@ -470,7 +490,7 @@ impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
470490
///
471491
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
472492
/// errors, for example.
473-
pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
493+
pub struct SharedContext<'p, 'sess, S: Stage> {
474494
/// The parse context, gives access to the session and the
475495
/// diagnostics context.
476496
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
@@ -538,7 +558,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
538558
pub(crate) tools: Vec<Symbol>,
539559
features: Option<&'sess Features>,
540560
sess: &'sess Session,
541-
stage: PhantomData<S>,
561+
stage: S,
542562

543563
/// *Only* parse attributes with this symbol.
544564
///
@@ -567,13 +587,14 @@ impl<'sess> AttributeParser<'sess, Early> {
567587
sym: Symbol,
568588
target_span: Span,
569589
target_node_id: NodeId,
590+
features: Option<&'sess Features>,
570591
) -> Option<Attribute> {
571592
let mut p = Self {
572-
features: None,
593+
features,
573594
tools: Vec::new(),
574595
parse_only: Some(sym),
575596
sess,
576-
stage: PhantomData,
597+
stage: Early { emit_errors: false },
577598
};
578599
let mut parsed = p.parse_attribute_list(
579600
attrs,
@@ -589,11 +610,55 @@ impl<'sess> AttributeParser<'sess, Early> {
589610

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

594654
impl<'sess, S: Stage> AttributeParser<'sess, S> {
595-
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
596-
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
655+
pub fn new(
656+
sess: &'sess Session,
657+
features: &'sess Features,
658+
tools: Vec<Symbol>,
659+
stage: S,
660+
) -> Self {
661+
Self { features: Some(features), tools, parse_only: None, sess, stage }
597662
}
598663

599664
pub(crate) fn sess(&self) -> &'sess Session {
@@ -604,6 +669,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
604669
self.features.expect("features not available at this point in the compiler")
605670
}
606671

672+
pub(crate) fn features_option(&self) -> Option<&'sess Features> {
673+
self.features
674+
}
675+
607676
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
608677
self.sess().dcx()
609678
}

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)