Skip to content

Commit 222551f

Browse files
committedApr 21, 2018
Auto merge of #50120 - alexcrichton:more-proc-macro-gates, r=petrochenkov
rustc: Tweak custom attribute capabilities This commit starts to lay some groundwork for the stabilization of custom attribute invocations and general procedural macros. It applies a number of changes discussed on [internals] as well as a [recent issue][issue], namely: * The path used to specify a custom attribute must be of length one and cannot be a global path. This'll help future-proof us against any ambiguities and give us more time to settle the precise syntax. In the meantime though a bare identifier can be used and imported to invoke a custom attribute macro. A new feature gate, `proc_macro_path_invoc`, was added to gate multi-segment paths and absolute paths. * The set of items which can be annotated by a custom procedural attribute has been restricted. Statements, expressions, and modules are disallowed behind two new feature gates: `proc_macro_expr` and `proc_macro_mod`. * The input to procedural macro attributes has been restricted and adjusted. Today an invocation like `#[foo(bar)]` will receive `(bar)` as the input token stream, but after this PR it will only receive `bar` (the delimiters were removed). Invocations like `#[foo]` are still allowed and will be invoked in the same way as `#[foo()]`. This is a **breaking change** for all nightly users as the syntax coming in to procedural macros will be tweaked slightly. * Procedural macros (`foo!()` style) can only be expanded to item-like items by default. A separate feature gate, `proc_macro_non_items`, is required to expand to items like expressions, statements, etc. Closes #50038 [internals]: https://internals.rust-lang.org/t/help-stabilize-a-subset-of-macros-2-0/7252 [issue]: #50038
·
1.88.01.27.0
2 parents e59f78f + 79630d4 commit 222551f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+265
-45
lines changed
 

‎src/librustc_resolve/macros.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,18 @@ impl<'a> Resolver<'a> {
397397

398398
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
399399
-> Result<Def, Determinacy> {
400+
if path.segments.len() > 1 {
401+
if !self.session.features_untracked().proc_macro_path_invoc {
402+
emit_feature_err(
403+
&self.session.parse_sess,
404+
"proc_macro_path_invoc",
405+
path.span,
406+
GateIssue::Language,
407+
"paths of length greater than one in macro invocations are \
408+
currently unstable",
409+
);
410+
}
411+
}
400412
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
401413
if def != Err(Determinacy::Undetermined) {
402414
// Do not report duplicated errors on every undetermined resolution.

‎src/libsyntax/ext/expand.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
514514
Some(kind.expect_from_annotatables(items))
515515
}
516516
AttrProcMacro(ref mac) => {
517+
self.gate_proc_macro_attr_item(attr.span, &item);
517518
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
518519
Annotatable::Item(item) => token::NtItem(item),
519520
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
@@ -522,7 +523,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
522523
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
523524
Annotatable::Expr(expr) => token::NtExpr(expr),
524525
})).into();
525-
let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
526+
let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
527+
let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
526528
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
527529
}
528530
ProcMacroDerive(..) | BuiltinDerive(..) => {
@@ -539,6 +541,49 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
539541
}
540542
}
541543

544+
fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
545+
let mut trees = tokens.trees();
546+
match trees.next() {
547+
Some(TokenTree::Delimited(_, delim)) => {
548+
if trees.next().is_none() {
549+
return delim.tts.into()
550+
}
551+
}
552+
Some(TokenTree::Token(..)) => {}
553+
None => return TokenStream::empty(),
554+
}
555+
self.cx.span_err(span, "custom attribute invocations must be \
556+
of the form #[foo] or #[foo(..)], the macro name must only be \
557+
followed by a delimiter token");
558+
TokenStream::empty()
559+
}
560+
561+
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
562+
let (kind, gate) = match *item {
563+
Annotatable::Item(ref item) => {
564+
match item.node {
565+
ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
566+
ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
567+
_ => return,
568+
}
569+
}
570+
Annotatable::TraitItem(_) => return,
571+
Annotatable::ImplItem(_) => return,
572+
Annotatable::ForeignItem(_) => return,
573+
Annotatable::Stmt(_) |
574+
Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
575+
Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
576+
Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
577+
};
578+
emit_feature_err(
579+
self.cx.parse_sess,
580+
gate,
581+
span,
582+
GateIssue::Language,
583+
&format!("custom attributes cannot be applied to {}", kind),
584+
);
585+
}
586+
542587
/// Expand a macro invocation. Returns the result of expansion.
543588
fn expand_bang_invoc(&mut self,
544589
invoc: Invocation,
@@ -665,6 +710,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
665710
self.cx.trace_macros_diag();
666711
kind.dummy(span)
667712
} else {
713+
self.gate_proc_macro_expansion_kind(span, kind);
668714
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
669715
call_site: span,
670716
callee: NameAndSpan {
@@ -695,6 +741,30 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
695741
}
696742
}
697743

744+
fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) {
745+
let kind = match kind {
746+
ExpansionKind::Expr => "expressions",
747+
ExpansionKind::OptExpr => "expressions",
748+
ExpansionKind::Pat => "patterns",
749+
ExpansionKind::Ty => "types",
750+
ExpansionKind::Stmts => "statements",
751+
ExpansionKind::Items => return,
752+
ExpansionKind::TraitItems => return,
753+
ExpansionKind::ImplItems => return,
754+
ExpansionKind::ForeignItems => return,
755+
};
756+
if self.cx.ecfg.proc_macro_non_items() {
757+
return
758+
}
759+
emit_feature_err(
760+
self.cx.parse_sess,
761+
"proc_macro_non_items",
762+
span,
763+
GateIssue::Language,
764+
&format!("procedural macros cannot be expanded to {}", kind),
765+
);
766+
}
767+
698768
/// Expand a derive invocation. Returns the result of expansion.
699769
fn expand_derive_invoc(&mut self,
700770
invoc: Invocation,
@@ -1370,6 +1440,9 @@ impl<'feat> ExpansionConfig<'feat> {
13701440
fn enable_custom_derive = custom_derive,
13711441
fn proc_macro_enabled = proc_macro,
13721442
fn macros_in_extern_enabled = macros_in_extern,
1443+
fn proc_macro_mod = proc_macro_mod,
1444+
fn proc_macro_expr = proc_macro_expr,
1445+
fn proc_macro_non_items = proc_macro_non_items,
13731446
}
13741447
}
13751448

0 commit comments

Comments
 (0)
Please sign in to comment.