summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_expand
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_expand')
-rw-r--r--compiler/rustc_expand/src/base.rs15
-rw-r--r--compiler/rustc_expand/src/config.rs30
-rw-r--r--compiler/rustc_expand/src/expand.rs69
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs10
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs50
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs23
8 files changed, 147 insertions, 55 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 4671adccc..8a251ea29 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -947,6 +947,8 @@ pub trait ResolverExpand {
/// HIR proc macros items back to their harness items.
fn declare_proc_macro(&mut self, id: NodeId);
+ fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem);
+
/// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &RegisteredTools;
}
@@ -965,7 +967,7 @@ pub trait LintStoreExpand {
type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
-#[derive(Clone, Default)]
+#[derive(Debug, Clone, Default)]
pub struct ModuleData {
/// Path to the module starting from the crate name, like `my_crate::foo::bar`.
pub mod_path: Vec<Ident>,
@@ -1108,6 +1110,7 @@ impl<'a> ExtCtxt<'a> {
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -1116,6 +1119,7 @@ impl<'a> ExtCtxt<'a> {
self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
}
+ #[track_caller]
pub fn create_err(
&self,
err: impl IntoDiagnostic<'a>,
@@ -1123,6 +1127,7 @@ impl<'a> ExtCtxt<'a> {
self.sess.create_err(err)
}
+ #[track_caller]
pub fn emit_err(&self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.sess.emit_err(err)
}
@@ -1133,10 +1138,12 @@ impl<'a> ExtCtxt<'a> {
/// Compilation will be stopped in the near future (at the end of
/// the macro expansion phase).
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
}
@@ -1154,7 +1161,7 @@ impl<'a> ExtCtxt<'a> {
// Fixme: does this result in errors?
self.expansions.clear();
}
- pub fn bug(&self, msg: &str) -> ! {
+ pub fn bug(&self, msg: &'static str) -> ! {
self.sess.parse_sess.span_diagnostic.bug(msg);
}
pub fn trace_macros(&self) -> bool {
@@ -1224,7 +1231,7 @@ pub fn resolve_path(
pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
- err_msg: &str,
+ err_msg: &'static str,
) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a, ErrorGuaranteed>, bool)>> {
// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
@@ -1262,7 +1269,7 @@ pub fn expr_to_spanned_string<'a>(
pub fn expr_to_string(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
- err_msg: &str,
+ err_msg: &'static str,
) -> Option<(Symbol, ast::StrStyle)> {
expr_to_spanned_string(cx, expr, err_msg)
.map_err(|err| {
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 4ff8e409d..3e43eae00 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -197,9 +197,11 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
config_tokens: false,
lint_node_id: ast::CRATE_NODE_ID,
};
- let attrs: ast::AttrVec =
- attrs.iter().flat_map(|attr| strip_unconfigured.process_cfg_attr(attr)).collect();
- if strip_unconfigured.in_cfg(&attrs) { attrs } else { ast::AttrVec::new() }
+ attrs
+ .iter()
+ .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
+ .take_while(|attr| !is_cfg(attr) || strip_unconfigured.cfg_true(attr).0)
+ .collect()
}
#[macro_export]
@@ -416,26 +418,34 @@ impl<'a> StripUnconfigured<'a> {
/// Determines if a node with the given attributes should be included in this configuration.
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
- attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
+ attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0)
}
- pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool {
+ pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
Ok(meta_item) => meta_item,
Err(mut err) => {
err.emit();
- return true;
+ return (true, None);
}
};
- parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
- attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features)
- })
+ (
+ parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+ attr::cfg_matches(
+ &meta_item,
+ &self.sess.parse_sess,
+ self.lint_node_id,
+ self.features,
+ )
+ }),
+ Some(meta_item),
+ )
}
/// If attributes are not allowed on expressions, emit an error for `attr`
#[instrument(level = "trace", skip(self))]
pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
- if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
+ if self.features.is_some_and(|features| !features.stmt_expr_attributes) {
let mut err = feature_err(
&self.sess.parse_sess,
sym::stmt_expr_attributes,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ce0093c7d..9850723a8 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1039,9 +1039,20 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
) -> Result<Self::OutputTy, Self> {
Ok(noop_flat_map(node, collector))
}
- fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
+ fn expand_cfg_false(
+ &mut self,
+ collector: &mut InvocationCollector<'_, '_>,
+ _pos: usize,
+ span: Span,
+ ) {
collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
}
+
+ /// All of the names (items) declared by this node.
+ /// This is an approximation and should only be used for diagnostics.
+ fn declared_names(&self) -> Vec<Ident> {
+ vec![]
+ }
}
impl InvocationCollectorNode for P<ast::Item> {
@@ -1148,6 +1159,27 @@ impl InvocationCollectorNode for P<ast::Item> {
collector.cx.current_expansion.module = orig_module;
res
}
+ fn declared_names(&self) -> Vec<Ident> {
+ if let ItemKind::Use(ut) = &self.kind {
+ fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
+ match &ut.kind {
+ ast::UseTreeKind::Glob => {}
+ ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
+ ast::UseTreeKind::Nested(nested) => {
+ for (ut, _) in nested {
+ collect_use_tree_leaves(&ut, idents);
+ }
+ }
+ }
+ }
+
+ let mut idents = Vec::new();
+ collect_use_tree_leaves(&ut, &mut idents);
+ return idents;
+ }
+
+ vec![self.ident]
+ }
}
struct TraitItemTag;
@@ -1382,8 +1414,15 @@ impl InvocationCollectorNode for ast::Crate {
fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
noop_visit_crate(self, visitor)
}
- fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, _span: Span) {
- self.attrs.clear();
+ fn expand_cfg_false(
+ &mut self,
+ collector: &mut InvocationCollector<'_, '_>,
+ pos: usize,
+ _span: Span,
+ ) {
+ // Attributes above `cfg(FALSE)` are left in place, because we may want to configure
+ // some global crate properties even on fully unconfigured crates.
+ self.attrs.truncate(pos);
// Standard prelude imports are left in the crate for backward compatibility.
self.items.truncate(collector.cx.num_standard_library_imports);
}
@@ -1685,8 +1724,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
node: &mut impl HasAttrs,
attr: ast::Attribute,
pos: usize,
- ) -> bool {
- let res = self.cfg().cfg_true(&attr);
+ ) -> (bool, Option<ast::MetaItem>) {
+ let (res, meta_item) = self.cfg().cfg_true(&attr);
if res {
// FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
// and some tools like rustdoc and clippy rely on that. Find a way to remove them
@@ -1694,7 +1733,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
self.cx.expanded_inert_attrs.mark(&attr);
node.visit_attrs(|attrs| attrs.insert(pos, attr));
}
- res
+
+ (res, meta_item)
}
fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
@@ -1715,9 +1755,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
return match self.take_first_attr(&mut node) {
Some((attr, pos, derives)) => match attr.name_or_empty() {
sym::cfg => {
- if self.expand_cfg_true(&mut node, attr, pos) {
+ let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
+ if res {
continue;
}
+
+ if let Some(meta_item) = meta_item {
+ for name in node.declared_names() {
+ self.cx.resolver.append_stripped_cfg_item(
+ self.cx.current_expansion.lint_node_id,
+ name,
+ meta_item.clone(),
+ )
+ }
+ }
Default::default()
}
sym::cfg_attr => {
@@ -1761,11 +1812,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
Some((attr, pos, derives)) => match attr.name_or_empty() {
sym::cfg => {
let span = attr.span;
- if self.expand_cfg_true(node, attr, pos) {
+ if self.expand_cfg_true(node, attr, pos).0 {
continue;
}
- node.expand_cfg_false(self, span);
+ node.expand_cfg_false(self, pos, span);
continue;
}
sym::cfg_attr => {
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index cb8b4899e..3593bed2d 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
}
Error(err_sp, msg) => {
let span = err_sp.substitute_dummy(self.root_span);
- self.cx.struct_span_err(span, msg.as_str()).emit();
+ self.cx.struct_span_err(span, msg.clone()).emit();
self.result = Some(DummyResult::any(span));
}
ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
@@ -222,7 +222,7 @@ pub(super) fn emit_frag_parse_err(
{
let msg = &e.message[0];
e.message[0] = (
- DiagnosticMessage::Str(format!(
+ DiagnosticMessage::from(format!(
"macro expansion ends with an incomplete expression: {}",
message.replace(", found `<eof>`", ""),
)),
@@ -313,9 +313,9 @@ pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: S
/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
/// other tokens, this is "unexpected token...".
-pub(super) fn parse_failure_msg(tok: &Token) -> String {
+pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> {
match tok.kind {
- token::Eof => "unexpected end of macro invocation".to_string(),
- _ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),),
+ token::Eof => Cow::from("unexpected end of macro invocation"),
+ _ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))),
}
}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 1c222fb4a..f0e67cfd5 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -249,6 +249,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> {
}
/// A single matcher position, representing the state of matching.
+#[derive(Debug)]
struct MatcherPos {
/// The index into `TtParser::locs`, which represents the "dot".
idx: usize,
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index e4c65a204..42cc0a6b1 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -223,8 +223,7 @@ fn expand_macro<'cx>(
// Replace all the tokens for the corresponding positions in the macro, to maintain
// proper positions in error reporting, while maintaining the macro_backtrace.
if tts.len() == rhs.tts.len() {
- tts = tts.map_enumerated(|i, tt| {
- let mut tt = tt.clone();
+ tts = tts.map_enumerated_owned(|i, mut tt| {
let rhs_tt = &rhs.tts[i];
let ctxt = tt.span().ctxt();
match (&mut tt, rhs_tt) {
@@ -535,7 +534,7 @@ pub fn compile_declarative_macro(
.pop()
.unwrap();
}
- sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+ sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
})
.collect::<Vec<mbe::TokenTree>>(),
_ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
@@ -628,6 +627,40 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
// after parsing/expansion. we can report every error in every macro this way.
}
+fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool {
+ if seq.separator.is_some() {
+ false
+ } else {
+ let mut is_empty = true;
+ let mut iter = seq.tts.iter().peekable();
+ while let Some(tt) = iter.next() {
+ match tt {
+ mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => {}
+ mbe::TokenTree::Token(t @ Token { kind: DocComment(..), .. }) => {
+ let mut now = t;
+ while let Some(&mbe::TokenTree::Token(
+ next @ Token { kind: DocComment(..), .. },
+ )) = iter.peek()
+ {
+ now = next;
+ iter.next();
+ }
+ let span = t.span.to(now.span);
+ sess.span_diagnostic.span_note_without_error(
+ span,
+ "doc comments are ignored in matcher position",
+ );
+ }
+ mbe::TokenTree::Sequence(_, sub_seq)
+ if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
+ || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne) => {}
+ _ => is_empty = false,
+ }
+ }
+ is_empty
+ }
+}
+
/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
@@ -644,16 +677,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
}
}
TokenTree::Sequence(span, seq) => {
- if seq.separator.is_none()
- && seq.tts.iter().all(|seq_tt| match seq_tt {
- TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
- TokenTree::Sequence(_, sub_seq) => {
- sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
- || sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
- }
- _ => false,
- })
- {
+ if is_empty_token_tree(sess, seq) {
let sp = span.entire();
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
return false;
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index b2bdf9c7e..40bfa3715 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -9,7 +9,7 @@ use rustc_session::parse::{feature_err, ParseSess};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::edition::Edition;
-use rustc_span::{Span, SyntaxContext};
+use rustc_span::Span;
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
@@ -72,7 +72,7 @@ pub(super) fn parse(
// `SyntaxContext::root()` from a foreign crate will
// have the edition of that crate (which we manually
// retrieve via the `edition` parameter).
- if span.ctxt() == SyntaxContext::root() {
+ if span.ctxt().is_root() {
edition
} else {
span.edition()
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 891e84a2f..ecd231511 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -2,7 +2,7 @@ use crate::base::ExtCtxt;
use pm::bridge::{
server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree,
};
-use pm::{Delimiter, Level, LineColumn};
+use pm::{Delimiter, Level};
use rustc_ast as ast;
use rustc_ast::token;
use rustc_ast::tokenstream::{self, Spacing::*, TokenStream};
@@ -648,23 +648,22 @@ impl server::Span for Rustc<'_, '_> {
Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize }
}
-
- fn start(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess().source_map().lookup_char_pos(span.lo());
- LineColumn { line: loc.line, column: loc.col.to_usize() }
+ fn start(&mut self, span: Self::Span) -> Self::Span {
+ span.shrink_to_lo()
}
- fn end(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess().source_map().lookup_char_pos(span.hi());
- LineColumn { line: loc.line, column: loc.col.to_usize() }
+ fn end(&mut self, span: Self::Span) -> Self::Span {
+ span.shrink_to_hi()
}
- fn before(&mut self, span: Self::Span) -> Self::Span {
- span.shrink_to_lo()
+ fn line(&mut self, span: Self::Span) -> usize {
+ let loc = self.sess().source_map().lookup_char_pos(span.lo());
+ loc.line
}
- fn after(&mut self, span: Self::Span) -> Self::Span {
- span.shrink_to_hi()
+ fn column(&mut self, span: Self::Span) -> usize {
+ let loc = self.sess().source_map().lookup_char_pos(span.lo());
+ loc.col.to_usize() + 1
}
fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {