fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
+ if path.segments.len() > 1 {
+ if !self.session.features_untracked().proc_macro_path_invoc {
+ emit_feature_err(
+ &self.session.parse_sess,
+ "proc_macro_path_invoc",
+ path.span,
+ GateIssue::Language,
+ "paths of length greater than one in macro invocations are \
+ currently unstable",
+ );
+ }
+ }
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
if def != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
Some(kind.expect_from_annotatables(items))
}
AttrProcMacro(ref mac) => {
+ self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
Annotatable::Expr(expr) => token::NtExpr(expr),
})).into();
- let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
+ let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
+ let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
}
}
+ fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
+ let mut trees = tokens.trees();
+ match trees.next() {
+ Some(TokenTree::Delimited(_, delim)) => {
+ if trees.next().is_none() {
+ return delim.tts.into()
+ }
+ }
+ Some(TokenTree::Token(..)) => {}
+ None => return TokenStream::empty(),
+ }
+ self.cx.span_err(span, "custom attribute invocations must be \
+ of the form #[foo] or #[foo(..)], the macro name must only be \
+ followed by a delimiter token");
+ TokenStream::empty()
+ }
+
+ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
+ let (kind, gate) = match *item {
+ Annotatable::Item(ref item) => {
+ match item.node {
+ ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
+ ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+ _ => return,
+ }
+ }
+ Annotatable::TraitItem(_) => return,
+ Annotatable::ImplItem(_) => return,
+ Annotatable::ForeignItem(_) => return,
+ Annotatable::Stmt(_) |
+ Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
+ Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
+ Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+ };
+ emit_feature_err(
+ self.cx.parse_sess,
+ gate,
+ span,
+ GateIssue::Language,
+ &format!("custom attributes cannot be applied to {}", kind),
+ );
+ }
+
/// Expand a macro invocation. Returns the result of expansion.
fn expand_bang_invoc(&mut self,
invoc: Invocation,
self.cx.trace_macros_diag();
kind.dummy(span)
} else {
+ self.gate_proc_macro_expansion_kind(span, kind);
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
}
}
+ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) {
+ let kind = match kind {
+ ExpansionKind::Expr => "expressions",
+ ExpansionKind::OptExpr => "expressions",
+ ExpansionKind::Pat => "patterns",
+ ExpansionKind::Ty => "types",
+ ExpansionKind::Stmts => "statements",
+ ExpansionKind::Items => return,
+ ExpansionKind::TraitItems => return,
+ ExpansionKind::ImplItems => return,
+ ExpansionKind::ForeignItems => return,
+ };
+ if self.cx.ecfg.proc_macro_non_items() {
+ return
+ }
+ emit_feature_err(
+ self.cx.parse_sess,
+ "proc_macro_non_items",
+ span,
+ GateIssue::Language,
+ &format!("procedural macros cannot be expanded to {}", kind),
+ );
+ }
+
/// Expand a derive invocation. Returns the result of expansion.
fn expand_derive_invoc(&mut self,
invoc: Invocation,
fn enable_custom_derive = custom_derive,
fn proc_macro_enabled = proc_macro,
fn macros_in_extern_enabled = macros_in_extern,
+ fn proc_macro_mod = proc_macro_mod,
+ fn proc_macro_expr = proc_macro_expr,
+ fn proc_macro_non_items = proc_macro_non_items,
}
}
(active, mmx_target_feature, "1.27.0", None, None),
(active, sse4a_target_feature, "1.27.0", None, None),
(active, tbm_target_feature, "1.27.0", None, None),
+
+ // Allows macro invocations of the form `#[foo::bar]`
+ (active, proc_macro_path_invoc, "1.27.0", None, None),
+
+ // Allows macro invocations on modules expressions and statements and
+ // procedural macros to expand to non-items.
+ (active, proc_macro_mod, "1.27.0", None, None),
+ (active, proc_macro_expr, "1.27.0", None, None),
+ (active, proc_macro_non_items, "1.27.0", None, None),
);
declare_features! (
//! Attributes producing expressions in invalid locations
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{duplicate, no_output};
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
// aux-build:attributes-included.rs
// ignore-stage1
-#![feature(proc_macro, rustc_attrs)]
+#![feature(proc_macro, rustc_attrs, proc_macro_path_invoc)]
#![warn(unused)]
extern crate attributes_included;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+// force-host
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn m(a: TokenStream) -> TokenStream {
+ a
+}
+
+#[proc_macro_attribute]
+pub fn a(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b
+}
// aux-build:bang_proc_macro2.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![allow(unused_macros)]
extern crate bang_proc_macro2;
// aux-build:bang_proc_macro.rs
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#[macro_use]
extern crate bang_proc_macro;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:proc-macro-gates.rs
+// gate-test-proc_macro_non_items
+// gate-test-proc_macro_path_invoc
+// gate-test-proc_macro_mod line
+// gate-test-proc_macro_expr
+// gate-test-proc_macro_mod
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+#[foo::a] //~ ERROR: paths of length greater than one
+fn _test() {}
+
+#[a] //~ ERROR: custom attributes cannot be applied to modules
+mod _test2 {}
+
+#[a = y] //~ ERROR: must only be followed by a delimiter token
+fn _test3() {}
+
+#[a = ] //~ ERROR: must only be followed by a delimiter token
+fn _test4() {}
+
+#[a () = ] //~ ERROR: must only be followed by a delimiter token
+fn _test5() {}
+
+fn main() {
+ #[a] //~ ERROR: custom attributes cannot be applied to statements
+ let _x = 2;
+ let _x = #[a] 2;
+ //~^ ERROR: custom attributes cannot be applied to expressions
+
+ let _x: m!(u32) = 3;
+ //~^ ERROR: procedural macros cannot be expanded to types
+ if let m!(Some(_x)) = Some(3) {
+ //~^ ERROR: procedural macros cannot be expanded to patterns
+ }
+ let _x = m!(3);
+ //~^ ERROR: procedural macros cannot be expanded to expressions
+ m!(let _x = 3;);
+ //~^ ERROR: procedural macros cannot be expanded to statements
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:proc-macro-gates.rs
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+// NB. these errors aren't the best errors right now, but they're definitely
+// intended to be errors. Somehow using a custom attribute in these positions
+// should either require a feature gate or not be allowed on stable.
+
+fn _test6<#[a] T>() {}
+//~^ ERROR: unknown to the compiler
+
+fn _test7() {
+ match 1 {
+ #[a] //~ ERROR: unknown to the compiler
+ 0 => {}
+ _ => {}
+ }
+}
+
+fn main() {
+}
// #41719
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
fn main() {
enum Foo {}
// gate-test-use_extern_macros
+#![feature(proc_macro_path_invoc)]
+
fn main() {
globnar::brotz!(); //~ ERROR non-ident macro paths are experimental
#[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental
#![feature(asm)]
#![feature(trace_macros, concat_idents)]
+#![feature(proc_macro_path_invoc)]
#[derive(Default)] //~ ERROR
enum OrDeriveThis {}
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod priv_nominal {
pub struct Pub;
// ignore-tidy-linelength
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
// error-pattern:type `for<'r> fn(&'r ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro)]
extern crate private_inferred_type as ext;
#![feature(associated_consts)]
#![feature(decl_macro)]
#![allow(private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod m {
fn priv_fn() {}
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
// aux-build:cond_plugin.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate cond_plugin;
// aux-build:hello_macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc, proc_macro_non_items)]
extern crate hello_macro;
// ignore-stage1
#![allow(warnings)]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_args;
use attr_args::attr_with_args;
#[attr_with_args(text = "Hello, world!")]
fn foo() {}
-#[::attr_args::identity
- fn main() { assert_eq!(foo(), "Hello, world!"); }]
+#[::attr_args::identity(
+ fn main() { assert_eq!(foo(), "Hello, world!"); })]
struct Dummy;
// aux-build:attr-on-trait.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_on_trait;
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_stmt, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
let args = args.to_string();
- assert_eq!(args, r#"( text = "Hello, world!" )"#);
+ assert_eq!(args, r#"text = "Hello, world!""#);
let input = input.to_string();
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
// aux-build:bang-macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate bang_macro;
use bang_macro::rewrite;
// aux-build:count_compound_ops.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate count_compound_ops;
use count_compound_ops::count_compound_ops;
// aux-build:derive-b.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate derive_b;
// aux-build:hygiene_example.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate hygiene_example;
use hygiene_example::hello;
// aux-build:issue-42708.rs
// ignore-stage1
-#![feature(decl_macro, proc_macro)]
+#![feature(decl_macro, proc_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;
// aux-build:negative-token.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate negative_token;
// ignore-stage1
// ignore-cross-compile
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro_def;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
macro m($S:ident, $x:ident) {
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
mod foo {
// aux-build:legacy_interaction.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#[allow(unused)]
extern crate legacy_interaction;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod bar {
mod baz {
// aux-build:my_crate.rs
// aux-build:unhygienic_example.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate unhygienic_example;
extern crate my_crate; // (b)
// aux-build:xcrate.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate xcrate;
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(proc_macro, decl_macro)]
+#![feature(proc_macro, decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
// aux-build:three-equals.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate three_equals;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S { x: u32 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub fn f() {}
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S;
// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate intercrate;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub macro m() { Vec::new(); ().clone() }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
fn f() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub trait T {
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
mod foo {
extern crate two_macros;