Allow Early stage to emit errors
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
@@ -202,7 +201,11 @@ pub trait Stage: Sized + 'static + Sealed {
|
||||
|
||||
fn parsers() -> &'static group_type!(Self);
|
||||
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
|
||||
fn emit_err<'sess>(
|
||||
&self,
|
||||
sess: &'sess Session,
|
||||
diag: impl for<'x> Diagnostic<'x>,
|
||||
) -> ErrorGuaranteed;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
@@ -214,8 +217,16 @@ impl Stage for Early {
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&early::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
sess.dcx().create_err(diag).delay_as_bug()
|
||||
fn emit_err<'sess>(
|
||||
&self,
|
||||
sess: &'sess Session,
|
||||
diag: impl for<'x> Diagnostic<'x>,
|
||||
) -> ErrorGuaranteed {
|
||||
if self.emit_errors {
|
||||
sess.dcx().emit_err(diag)
|
||||
} else {
|
||||
sess.dcx().create_err(diag).delay_as_bug()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,20 +239,29 @@ impl Stage for Late {
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&late::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
fn emit_err<'sess>(
|
||||
&self,
|
||||
tcx: &'sess Session,
|
||||
diag: impl for<'x> Diagnostic<'x>,
|
||||
) -> ErrorGuaranteed {
|
||||
tcx.dcx().emit_err(diag)
|
||||
}
|
||||
}
|
||||
|
||||
/// used when parsing attributes for miscellaneous things *before* ast lowering
|
||||
pub struct Early;
|
||||
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: bool,
|
||||
}
|
||||
/// used when parsing attributes during ast lowering
|
||||
pub struct Late;
|
||||
|
||||
/// Context given to every attribute parser when accepting
|
||||
///
|
||||
/// Gives [`AttributeParser`]s enough information to create errors, for example.
|
||||
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
pub struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
pub(crate) shared: SharedContext<'f, 'sess, S>,
|
||||
/// The span of the attribute currently being parsed
|
||||
pub(crate) attr_span: Span,
|
||||
@@ -257,7 +277,7 @@ pub(crate) 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 {
|
||||
S::emit_err(&self.sess, diag)
|
||||
self.stage.emit_err(&self.sess, diag)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
///
|
||||
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
|
||||
/// errors, for example.
|
||||
pub(crate) struct SharedContext<'p, 'sess, S: Stage> {
|
||||
pub struct SharedContext<'p, 'sess, S: Stage> {
|
||||
/// The parse context, gives access to the session and the
|
||||
/// diagnostics context.
|
||||
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
||||
@@ -540,7 +560,7 @@ pub struct AttributeParser<'sess, S: Stage = Late> {
|
||||
pub(crate) tools: Vec<Symbol>,
|
||||
features: Option<&'sess Features>,
|
||||
sess: &'sess Session,
|
||||
stage: PhantomData<S>,
|
||||
stage: S,
|
||||
|
||||
/// *Only* parse attributes with this symbol.
|
||||
///
|
||||
@@ -569,13 +589,14 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
sym: Symbol,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
) -> Option<Attribute> {
|
||||
let mut p = Self {
|
||||
features: None,
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
parse_only: Some(sym),
|
||||
sess,
|
||||
stage: PhantomData,
|
||||
stage: Early { emit_errors: false },
|
||||
};
|
||||
let mut parsed = p.parse_attribute_list(
|
||||
attrs,
|
||||
@@ -591,11 +612,55 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
|
||||
parsed.pop()
|
||||
}
|
||||
|
||||
pub fn parse_single<T>(
|
||||
sess: &'sess Session,
|
||||
attr: &ast::Attribute,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: bool,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
|
||||
template: &AttributeTemplate,
|
||||
) -> T {
|
||||
let mut parser = Self {
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
parse_only: None,
|
||||
sess,
|
||||
stage: Early { emit_errors },
|
||||
};
|
||||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
};
|
||||
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
|
||||
let path = meta_parser.path();
|
||||
let args = meta_parser.args();
|
||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: &mut parser,
|
||||
target_span,
|
||||
target_id: target_node_id,
|
||||
emit_lint: &mut |_lint| {
|
||||
panic!("can't emit lints here for now (nothing uses this atm)");
|
||||
},
|
||||
},
|
||||
attr_span: attr.span,
|
||||
template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
};
|
||||
parse_fn(&mut cx, args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
|
||||
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
|
||||
pub fn new(
|
||||
sess: &'sess Session,
|
||||
features: &'sess Features,
|
||||
tools: Vec<Symbol>,
|
||||
stage: S,
|
||||
) -> Self {
|
||||
Self { features: Some(features), tools, parse_only: None, sess, stage }
|
||||
}
|
||||
|
||||
pub(crate) fn sess(&self) -> &'sess Session {
|
||||
@@ -606,6 +671,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
self.features.expect("features not available at this point in the compiler")
|
||||
}
|
||||
|
||||
pub(crate) fn features_option(&self) -> Option<&'sess Features> {
|
||||
self.features
|
||||
}
|
||||
|
||||
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
|
||||
self.sess().dcx()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user