Rust: Problema de seguimiento para RFC 1566: macros de procedimiento

Creado en 14 dic. 2016  ·  184Comentarios  ·  Fuente: rust-lang/rust

Estado actual

Este problema se ha resuelto en favor de problemas de seguimiento más detallados.

~ Descripción actualizada ~

Próximos pasos:

  • [x] [Estabilizar use_extern_macros ] (https://github.com/rust-lang/rust/pull/50911)

    • esperando en el cráter

  • [] Estabilizar la función proc_macro

Posibles obstáculos de estabilización

Descripción original

RFC .

Este RFC propone una evolución del sistema de macros procedimentales de Rust (también conocido como sintaxis
extensiones, también conocido como complementos del compilador). Este RFC especifica la sintaxis de la definición
de macros de procedimiento, una vista de alto nivel de su implementación en el compilador,
y describe cómo interactúan con el proceso de compilación.

En el nivel más alto, las macros se definen implementando funciones marcadas con
un atributo #[macro] . Las macros operan en una lista de tokens proporcionada por el
compilador y devuelve una lista de tokens por los que se reemplaza el uso de la macro. Nosotros
Proporcionar instalaciones de bajo nivel para operar con estos tokens. Nivel más alto
las instalaciones (por ejemplo, para analizar tokens en un AST) deben existir como cajas de biblioteca.

Hoja de ruta: https://github.com/rust-lang/rust/issues/38356#issuecomment -274377210.


Tareas

  • [x] Implementar #[proc_macro_attribute] (PR # 38842).

    • [x] Arreglo # 39347 (PR # 39572).

    • [x] Arreglo # 39336 (PR # 44528).

  • [x] Implementar #[proc_macro] (PR # 40129).
  • [x] Identifique y recopile los usos de proc_macro_derive s en el InvocationCollector (PR # 39391).
  • [x] Soporta importaciones macro-expandidas proc_macro_derive .

    • Por ejemplo:

#[derive(Trait, OtherTrait)] struct S; // Both these derives should resolve
macro_rules! m { () => {
    #[macro_use(Trait)] extern crate derives;
    use derives::OtherTrait; // this kind of import is gated behind `#![feature(proc_macro)]`
} }
m!();
  • [] Expandir elementos antes de expandir aplicados proc_macro_derive s (PR # 48465).
  • [x] Implementar advertencias para importaciones de #[macro_use] no utilizadas (PR # 39060).
  • [x] Refactorice el analizador para consumir árboles de tokens (PR # 39118).
  • [x] Limpiar TokenStream en preparación para una refactorización adicional (PR # 39173).
  • [x] Quite TokenTree::Sequence (PR # 39419).
  • [x] Use TokenStream s en lugar de Vec<TokenTree> en la variante tokenstream::TokenTree Delimited (PR # 40202).
  • [x] Use Path sy TokenStream s en ast::Attribute s (PR # 40346).

    • [x] Admite rutas no triviales en macros de atributos / derivaciones (por ejemplo, #[foo::bar] , #[derive(foo::Bar)] ).

  • [x] Incluya información de higiene con todos los tokens, no solo con los identificadores (PR # 40597).
  • [x] Implemente una API mínima por proc_macro::TokenStream como se describe en el RFC (PR # 40939).

    • [x] Incluya la fuente TokenStream s para fragmentos AST interpolados en Token::Interpolated tokens.

    • [x] Incluya un TokenStream cotizador proc_macro::quote! detrás de la puerta de función proc_macro .

  • [x] Proporcionar una forma para que los autores de proc_macro creen expansiones que usen elementos en una caja predeterminada foo sin requerir que el usuario macro incluya extern crate foo; en la raíz de la caja (PR # 40939).

    • [] Mejorar la ergonomía.

  • [] Incluya la fuente TokenStream s para los elementos en el AST.
  • [] Macros de comprobación de estabilidad (proc-) (problema nº 34079).
  • [x] Permitir que la macro proc inicialice un campo privado con un valor def_site (problema # 47311). (PR # 48082)
  • [x] Inconsistencia entre el acceso al campo de estructura reforzada vs estructura de tupla en la macro proc (problema # 47312). (PR # 48083)
  • [] Haga que std esté disponible para procesar la raíz de la macro en la fase 1 (número 47314).
  • [x] Mejora el error de sintaxis no válida dentro de proc_macro::quote! (problema # 47315).
  • [] Inconsistencia entre Display e IntoIterator para un TokenStream que contiene un módulo (problema # 47627).
  • [x] # [cfg_attr] hace que .to_string () y TokenStream no estén de acuerdo (problema # 48644).
  • [x] Lista de deseos para libproc_macro (lista de verificación en # 47786).
A-macros A-macros-1.2 A-macros-2.0 A-plugin B-RFC-approved B-unstable C-tracking-issue T-lang T-libs finished-final-comment-period

Comentario más útil

Ok, este problema es masivo y ha llegado al punto en que no creo que sea demasiado útil mantener abierto más y rastrear las API. Con ese fin, he abierto https://github.com/rust-lang/rust/pull/54728 que divide este problema en varios problemas de seguimiento más detallados:

En este punto, voy a cerrar esto, pero si me he olvidado de separar cualquier otro problema de seguimiento, ¡avíseme! Ciertamente puedo abrir más seguimientos

Todos 184 comentarios

cc @nrc @jseyfried

Me encantaría que #[proc_macro_attribute] se implemente pronto. Ya tengo un prototipo y uso de prueba que aproveché antes de darme cuenta de que todavía no hay soporte para el compilador: unamused::

Prototipo: https://github.com/abonander/anterofit/blob/proc_macro/macros/src/lib.rs
Ejemplo / Prueba: https://github.com/abonander/anterofit/blob/proc_macro/examples/post_service_proc_macro.rs

Tareas

(dtolnay edit: movió la lista de verificación al OP)

cc @nrc @petrochenkov @durka @Ralith

@jseyfried Me encontré con un problema en el que si una macro heredada y un atributo con el mismo nombre se importan al mismo alcance, al intentar usar el atributo se produce un error de que las macros no se pueden usar como atributos. ¿Podemos hacer que esto funcione para que ambos puedan estar en el mismo alcance y puedan usarse como se pretende?

@abonander Todas las macros (bang, attribute y derive) comparten el mismo espacio de nombres, por lo que no podemos usar dos macros diferentes con el mismo nombre en el mismo ámbito. Sin embargo, podríamos mejorar ese mensaje de error: ¿podría abrir un problema?

Siento llegar tarde a la fiesta. Estoy contento con la dirección de exponer tokens en lugar de un AST, pero tengo algunas preocupaciones sobre la API TokenStream específica propuesta en el RFC :

pub enum TokenKind {
    Sequence(Delimiter, TokenStream),

    // The content of the comment can be found from the span.
    Comment(CommentKind),

    // `text` is the string contents, not including delimiters. It would be nice
    // to avoid an allocation in the common case that the string is in the
    // source code. We might be able to use `&'codemap str` or something.
    // `raw_markers` is for the count of `#`s if the string is a raw string. If
    // the string is not raw, then it will be `None`.
    String { text: Symbol, raw_markers: Option<usize>, kind: StringKind },

    // char literal, span includes the `'` delimiters.
    Char(char),

    // These tokens are treated specially since they are used for macro
    // expansion or delimiting items.
    Exclamation,  // `!`
    Dollar,       // `$`
    // Not actually sure if we need this or if semicolons can be treated like
    // other punctuation.
    Semicolon,    // `;`
    Eof,          // Do we need this?

    // Word is defined by Unicode Standard Annex 31 -
    // [Unicode Identifier and Pattern Syntax](http://unicode.org/reports/tr31/)
    Word(Symbol),
    Punctuation(char),
}

pub enum StringKind {
    Regular,
    Byte,
}

No está claro si esta API tenía la intención de ser un plan completo que se aceptó cuando se fusionó el RFC, o simplemente un ejemplo que se elaborará más adelante.

Generalmente, esto parece estar lejos de la sintaxis "normal" de Rust aceptada por el compilador fuera de las macros. Mientras que algunas macros querrán analizar algún lenguaje específico de dominio ad-hoc, otras querrán analizar la sintaxis "actual de Rust" y darle sentido.

  1. (Menor) No creo que Eof sea ​​necesario. Un Iterator presumiblemente se usará para, bueno, iterar sobre un TokenStream y Iterator::next ya devuelve None para señalar el final de la iteración.

  2. (Menor) No creo que Exclamation , Dollar o Semicolon sean necesarios. Hacer coincidir Punctuation('!') por ejemplo, no es más difícil.

  3. (Menor) Como otros han mencionado en el RFC PR, es posible que deseemos omitir comentarios que no sean comentarios de documentos. (Cualquier caso de uso que quiera preservar el comentario probablemente también quiera preservar los espacios en blanco).

  4. Por lo que puedo decir, qué hacer con los operadores de varios caracteres (que probablemente deberían ser un solo token cada uno) sigue siendo una pregunta abierta. Una posible solución se discute en los comentarios de relaciones públicas, pero parece que no se incluyó en el texto RFC.

  5. Faltan literales numéricos. ¿Se supone que las macros analizan [Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')] por sí mismas para evaluar un literal? Ni siquiera pueden usar str::parse::<f32> para hacer eso, ya que la sintaxis que acepta no es la misma que la sintaxis literal de Rust (que puede tener _ en el medio, por ejemplo).

    Imagino que aquí hay una preocupación por la estabilidad. ¿Podemos introducir nuevos tipos numéricos como u128 / i128 (y posiblemente en el futuro f128 , u256 ,…) y sus literales, sin romper los cambios en la API de tokens? Una forma de hacer esto posible podría ser:

    struct IntegerLiteral { negative: bool, decimal_digits: String, type_suffix: Option<String> }
    impl TryInto<u32> IntegerLiteral { type Err = OutOfRange; /* … */ }
    // Other impls for integer types supported in this compiler version
    
    // Something similarly for floats
    

    O quizás alguna otra cosa. Pero no creo que "fingir que los números no existen" sea una buena manera de hacerlo.

  6. // Word está definido por el anexo 31 del estándar Unicode -

    Esta definición debe ser más precisa que eso. UAX 31 especifica un par de variaciones diferentes de sintaxis de identificador, y ninguna de ellas se llama "palabra". Pero elegir qué variación exacta queremos es la razón por la que los identificadores que funciones en este momento.

    En cambio, creo que esto debería definirse como "lo que el compilador actual acepte como identificador o palabra clave" (que puede cambiar según # 28979). Quizás con una API pública pub fn is_identifier(&str) -> bool en libmacro.

  7. Las cadenas Unicode y los literales de cadenas de bytes comparten una única variante de token, lo que creo que es incorrecto ya que las representaciones de memoria de sus valores tienen diferentes tipos ( str vs [u8] ). Tampoco está claro si el componente text: Symbol está destinado a ser una porción literal del código fuente o el valor después de resolver los escapes de barra invertida. Creo que definitivamente debería ser lo último. (A modo de comparación, Char(char) tiene que ser el último ya que \u{A0} requiere más de un char para representarlo literalmente).

otra forma de escribir macros de alto nivel sería usar lisp como macros, pero esto necesitaría una representación de expresión s para todo el ast de rust.

@SimonSapin ,

Como otros han mencionado en el RFC PR, es posible que deseemos omitir comentarios que no sean comentarios de documentos. (Cualquier caso de uso que quiera preservar el comentario probablemente también quiera preservar los espacios en blanco).

Por favor no lo hagas. Tengo un caso de uso en el que quiero usar (aunque no preservar; en su lugar, se escribirán en un producto de compilación separado) comentarios en la sintaxis.

Específicamente, quiero crear macros de traducción que carguen traducciones de una cadena desde un archivo (s) fuente separado y me gustaría generar una lista de cadenas para traducir como subproducto en la compilación de depuración. Y debe haber una forma de incluir comentarios que se emitirán en esa lista (rust-locale / rust-locale # 19). Por lo tanto, tiene sentido usar la sintaxis de comentarios y la macro necesita verlos.

Estoy de acuerdo con los otros puntos de esa publicación.

@ jan-hudec
Incluso si no tuviéramos un TokenKind::Comment , aún podría usar comentarios mirando el contenido de los intervalos entre tokens consecutivos.

No creo que no deberíamos tener TokenKind::Comment para alentar a las macros de procedimiento a ignorar los comentarios para que los usuarios sean libres de agregar comentarios a las invocaciones de macros sin preocuparse por cambiar la semántica.

@ jan-hudec ¿Hay alguna razón por la que los atributos no funcionen con su solución?

@abonander , los atributos no tienen ningún sentido. Las cadenas traducibles actúan como literales, no como elementos. Pero extraerlos durante la compilación sería solo por conveniencia; siempre se puede hacer como análisis por separado (y de hecho, puede terminar siendo así, porque necesito ver _todos_ en la caja y la compilación incremental rompería eso).

Quiero hacer una macro de procedimiento que se base en la derivación de serde (y por lo tanto llama directamente a las funciones de tokenstream de serde) pero no hay forma de decir que quiero consumir la derivación de serde como una biblioteca en lugar de una macro de procedimiento. Esto no es exclusivo para derivar macros, puedo ver que también se desea algo similar para las macros de procedimiento 'normales'.

Mi única solución en este momento parece ser bifurcar serde_derive.

El problema es este mensaje de error de rustc:

error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type

Es fácil eliminar eso y hacer que funcione, pero también hay cierta complejidad que no estoy seguro de cómo resolver: una caja de macro de procedimiento podría querer usar el proc-macro derivado de otra caja de macro de procedimiento, así como llamar a las funciones para generar la derivación para un usuario intermedio. Como se veria eso? ¿Hay algo similar a esto en este momento, donde una caja se puede vincular de dos maneras diferentes a petición del consumidor?

@aidanhs

una caja de macro de procedimiento podría querer usar la derivación proc-macro de otra caja de macro de procedimiento, así como llamar a las funciones para generar la derivación para un usuario intermedio. Como se veria eso?

No puede acceder a las funciones (ni a nada más que a las macros de procedimiento) desde una caja proc-macro . Si desea utilizar las funciones TokenStream -> TokenStream y las macros de procedimiento correspondientes, deberá colocar las funciones TokenStream -> TokenStream en una caja separada, que no sea proc-macro , y luego tener una caja de proc-macro que simplemente delega esas funciones.

Este RFC se implementará principalmente una vez que llegue el número 40939.

Proporcionar una forma para que los autores de proc_macro creen expansiones que usen elementos en una caja predeterminada foo sin requerir que el usuario macro incluya extern crate foo; en la raíz de la caja

Supongamos que quiero presentar una caja única, que contiene elementos que no son macro y una macro de procedimiento que se refiere a dichos elementos. Cuando aterrice el # 40939, ¿será este patrón de tres cajas la forma idiomática de lograr este objetivo?

  1. Ponga todos los elementos no macro en foo_runtime
  2. Implemente la macro de procedimiento en foo_macros , refiriéndose a los símbolos en foo_runtime según sea necesario
  3. Agregue una caja de "fachada" final foo que pub use s los elementos de foo_runtime y foo_macros

    • Esta es la única caja que el usuario importará directamente.

    • Esto funciona porque el sistema de higiene corrige las macros para que apunten a la caja correcta.

Lo pregunto porque mi caso de uso implica la importación de dos cajas , y sería genial para la usabilidad si pudiera salirme con una sola.

@lfairy Creo que un patrón de "dos cajas" será la forma idiomática:

  1. Coloque todos los elementos que no sean macro en foo
  2. Implemente la macro de procedimiento en foo_macros , refiriéndose a los símbolos en foo según sea necesario, p. Ej.
#[proc_macro]
fn m(_: TokenStream) -> TokenStream {
    quote! {
        extern crate foo; // due to hygiene, this is never a conflict error
        foo::f();
        // --- or just --- (if/when we get the sugar)
        $universe::foo::f();
    }
}
  1. pub use artículos de foo_macros en foo .

Esto funciona porque el sistema de higiene corrige las macros para que apunten a la caja correcta.

Reexportar una macro de procedimiento en una caja diferente no afecta cómo se resuelven los nombres de la macro de procedimiento.

@jseyfried : ¿Sabe si este truco de reexportación también funciona con

@ colin-kiegel
Las cajas de derivación personalizadas son solo cajas de macro de proceso que tienen solo #[proc_macro_derive] s.
Con #[feature(proc_macro)] , puede reexportar derivadas personalizadas en cajas ordinarias, al igual que puede reexportar otras macros de proceso.

@jseyfried Soy consciente de la situación en este momento, hice la pregunta porque no creo que sea ideal y esperaba tener una discusión al respecto. En la situación que describe, 'delegar' / reutilizar a las macros de procedimiento de otra caja se convierte en una cuestión de convencer al autor de la macro (en este caso, serde) para dividir sus macros de procedimiento en dos cajas. Si puedo llamar a macros de procedimiento como funciones normales, el autor de la caja original ni siquiera necesita saber que estoy usando su caja.

Dicho esto, reconozco el peligro de compatibilidad: el árbol de tokens exacto generado por una macro se convierte en parte de la interfaz estable, por lo que si serde cambia la forma en que generan Derive en una versión de parche y he escrito una macro frágil, mi La macro se romperá para cada nuevo usuario de mi caja (a diferencia de una macro frágil en el caso actual, donde en el peor de los casos solo funcionará para entradas específicas, pero de manera consistente).

@jseyfried

¿Esto extrae foo de la lista de carga actual? Eso suena mal (es decir, ¿hará algo particularmente estúpido si hay 2 cajas llamadas foo vinculadas al binario actual?).

@aidanhs Eso sería un importante cambio / adición de lenguaje que justificaría su propio RFC.

@ arielb1

¿Esto extrae foo de la lista de carga actual? Eso suena mal

Sí, lamentablemente, los nombres extern crate citados no son higiénicos, es decir, la resolución depende de qué nombres de cajas estén dentro del alcance donde se usa la macro de procedimiento. Podemos mitigar esto usando el truco de reexportación (es decir, reexportando foo_macros en foo para que sepamos que foo estará dentro del alcance), pero eso no protege contra errores de ambigüedad cuando hay dos cajas llamadas foo .

Creo que la mejor solución aquí es agregar las dependencias de la fase 1 (es decir, el host wrt objetivo vs el objetivo) a las cajas Cargo.toml para proc-macro través de un argumento de línea de comando --target-extern . Esto nos permitiría enumerar explícitamente los nombres extern crate dentro del alcance dentro de quote! .

@jseyfried

La idea es que una caja proc-macro tendría una dependencia en sus metadatos "objetivo", ¿verdad?

@ arielb1 Sí, exactamente.

Este RFC se implementará principalmente una vez que llegue el número 40939.

@jseyfried Como en, ¿listo para ser estabilizado cuando aterrice ese PR? Si no es así, ¿qué quedaría bloqueando la estabilización? Simplemente no quiero que esta sea una característica más en la que se sienta que tenemos el 95% del camino hacia la implementación y la gente se emociona, y luego las cosas se apagan de manera anticlimática.

Como en, ¿listo para estabilizarse cuando aterrice ese RP?

No, queremos obtener algo de experiencia con la API antes de estabilizar y tal vez una higiene a prueba de futuro para los nombres de extern crate (es decir, abordar este problema que señaló @ arielb1 ).

Probablemente queramos hacer cambios importantes en esta API; @eddyb ha propuesto / considerado generalizar OpKind a todos los árboles de tokens. Además, podríamos cambiar la forma en que manejamos los comentarios de documentos, los literales de punto flotante, etc. En general, la API en este PR no está lo suficientemente madura como para considerar la estabilización todavía.

@bstrie, lamentablemente, el RFC para acelerar la estabilización de macro de proceso (con una API limitada en la que, por ejemplo, los flujos de token solo son accesibles a través de su representación de cadena), como la estabilización de macro de derivación ha fallado: https://github.com/rust-lang/rfcs/ tirar / 1913

@ est31 Pospuesto, más bien: después de un poco de experiencia con esta API, podríamos acordar un subconjunto en el que podemos acordar acelerar a estable.

La API basada en String interactúa mal con las macros declarativas 2.0 y ya es limitante hoy en día, incluso sin macros 2.0 y solo con #[derive] s. Queremos evitar la proliferación de la API basada en String tanto como sea posible para evitar problemas a medida que las personas migran a macros 2.0.

Abrí un problema por #[proc_macro_attribute] aparentemente no se expandió en los métodos de rasgos (¿tal vez elementos de rasgos en general?)

Dado que este es ahora el problema de seguimiento de la caja proc_macro y sus nuevas API, pensé en escribir algunas ideas también. He publicado una caja llamada proc-macro2 que está destinada a ser exactamente la misma que la caja proc_macro en el árbol, excepto que proporciona la capacidad de compilar en Rust estable. Luego, también tiene la capacidad de usar una función para compilar en Rust todas las noches para obtener el beneficio de una mejor información de intervalo. Esa biblioteca está destinada a convertirse en la base de otras bibliotecas como syn , y en el desarrollo de syn encontramos algunas deficiencias que tal vez deseemos abordar en proc_macro directamente:

  • No hay Literal constructor

    • Cuerdas sin procesar - r###" foo "###

    • Cadenas de bytes sin formato - rb#" foo "#

    • Literales de bytes - b'x'

    • Comentarios de documentos: actualmente se representan como el token Literal .

  • No hay forma de inspeccionar un Literal y extraer su valor. En este momento confiamos en la caja de texto literale para to_string a literal y lo volvemos a analizar, pero esta información en teoría ya está almacenada en el Literal y sería bueno poder hacerlo acceder a él.
  • El mapeo de tokens en algunos casos puede interpretarse como un poco extraño. Es decir, en este momento, los comentarios de documentos se asignan al tipo Literal .

Creo que desde entonces se han abordado todas las demás preocupaciones que comienzan aquí .

Encontré una rotura al probar con #![feature(proc_macro)] que afecta a las derivaciones personalizadas que tienen #[proc_macro_derive(foo, attributes(foo))] . Es decir, una derivación personalizada que tiene el nombre de un atributo que es el mismo que la derivada personalizada. Una de esas cajas es la mía: derive-error-chain, que tiene #[derive(error_chain)] #[error_chain(...)] struct ErrorKind { ... } . Otro es derivar-nuevo, que tiene #[derive(new)] #[new] struct S; . No sé si hay otros.

Para un código como este, el compilador se queja en el segundo atributo de que "foo" is a derive mode . ¿Es esto intencional o se puede arreglar? Si es intencional, necesito prepararme para cambiar el nombre de mi derivado personalizado a ErrorChain o algo así.

@Arnavion
Esto fue intencional en general, dado que proc_macro_attribute s deben expandirse antes de las derivaciones, si new fueran proc_macro_attribute entonces la expansión sería ambigua. Sería posible permitir específicamente que new sea ​​un proc_macro_derive , pero no estoy seguro de que valga la pena (también podría ser un peligro de compatibilidad futura).

Esto fue intencional en general, dado que proc_macro_attributes debe expandirse antes de las derivaciones, si new fueran proc_macro_attribute , la expansión sería ambigua.

Bien, cambiaré el nombre de #[derive(error_chain)] a #[derive(ErrorChain)] .

Sería posible permitir específicamente que new sea ​​un proc_macro_derive , pero no estoy seguro de que valga la pena (también podría ser un peligro de compatibilidad futura).

Claro, no estaba pidiendo new para una caja especial. Fue solo un ejemplo de uno de los dos proc_macro_derive s que conozco que están rotos por esto.

@Arnavion Lo siento, mi último comentario no fue el más claro; no me refería específicamente al caso especial new sino a permitir #[derive(some_macro)] #[some_attr] struct S; cuando some_attr resuelve en proc_macro_derive . Cuando some_attr resuelve en proc_macro_attribute , esto debería ser un error de ambigüedad; hoy, es un error de ambigüedad si some_attr resuelve en cualquier macro.

Sí lo tengo.

( Espero que este sea el lugar adecuado para una pregunta como esta )

¿Cuál es el estado de esto?

  • [] Proporcionar una forma para que los autores de proc_macro creen expansiones que usen elementos en una caja predeterminada foo sin requerir que el usuario macro incluya extern crate foo; en la raíz de la caja (PR # 40939 ).

El PR ha aterrizado, pero la casilla aún no está marcada. @jseyfried mencionó algo aquí y parece funcionar. Sin embargo, no parece funcionar con use en absoluto:

let call_site_self = TokenTree {
    kind: TokenNode::Term(Term::intern("self")),
    span: Span::call_site(),
};
quote! {
    extern crate foo; // due to hygiene, this is never a conflict error

    // Neither of those works    
    use foo::f;
    use self::foo::f;
    use $call_site_self::foo:f;
}

¿Me estoy perdiendo de algo? ¿Cuál es la forma idiomática de use símbolos de una caja externa importada en la macro?

No puede usar use consulte https://github.com/rust-lang/rfcs/issues/959. Pero para una macro no es realmente una desventaja usar la ruta completamente calificada cada vez. (Excepto por los rasgos, creo)

@parched Gracias por vincular este otro problema. Mi caso de uso fue el siguiente:

En mi macro, quiero permitir que el usuario escriba algo similar a un match-matcher. Específicamente, el usuario escribe un Term y esto puede ser una variante de una enumeración o un nombre de variable simple que une el valor de coincidencia. Para escribir un pseudocódigo con la sintaxis macro_rules! :

macro_rules foo {
    ($matcher:ident) => {
        match something() {
            $matcher => {}
            _ => {}
        }
    }
}

Ahora quiero que el usuario pueda especificar el nombre de la variante sin el nombre de enumeración. Por lo tanto, insertaría una declaración use my_crate::AnEnum::*; en el código generado. Pero como esto no es posible (en este momento), necesito verificar por mí mismo si $matcher es una variante de la enumeración o no.

Espero que mi explicación sea comprensible. Solo quería dar otro caso de uso para use en código generado por macro.

@LukasKalbertodt ¿Podrías usar my_crate::AnEnum::$matcher => {} en match ?
No importa, yo soy el problema, creo que necesitaremos https://github.com/rust-lang/rfcs/issues/959 para eso.

@jseyfried No: $matcher puede ser un nombre de variante (en cuyo caso su solución funcionaría) o un nombre de variable simple como match x { simple_var_name => {} } . En el último caso, no funcionaría AFAICT. (por cierto, solo quería mencionar otro caso de uso para mostrar que usar use es importante)

@jseyfried

Esto fue intencional en general, dado que proc_macro_attributes debe expandirse antes de las derivaciones, si new fueran proc_macro_attribute , la expansión sería ambigua.

Bien, cambiaré el nombre de #[derive(error_chain)] a #[derive(ErrorChain)] .

Parece que los atributos de las derivaciones personalizadas también entran en conflicto con las macros macro_rules , en lugar de anularlas como lo hacen las derivadas personalizadas según el orden de importación. Es decir, este código compila:

#![feature(proc_macro)]
#[macro_use] extern crate error_chain; // macro_rules! error_chain
#[macro_use] extern crate derive_error_chain; // #[proc_macro_derive(error_chain, attributes(error_chain))]

#[derive(error_chain)] // No error. Resolves to custom derive
enum ErrorKind {
    /*#[error_chain]*/ // (1) As discussed above, can't use this any more since it conflicts with the name of the custom derive
    Foo,
}

Esto coincide con el comportamiento de estable actual Rust, con la excepción de que (1) funciona en el establo. Incluso he documentado explícitamente que los usuarios que deseen usar #[macro_use] con la caja error-chain deberán importarlo antes de importar derive-error-chain .

Pero incluso si cambio el nombre de la derivación personalizada a ErrorChain para que (1) funcione con la función proc_macro (que ya es un cambio importante para el código estable):

#![feature(proc_macro)]
#[macro_use] extern crate error_chain; // macro_rules! error_chain
#[macro_use] extern crate derive_error_chain; // #[proc_macro_derive(ErrorChain, attributes(error_chain))]

#[derive(ErrorChain)] // Unique name, so no error
enum ErrorKind {
    #[error_chain] // (2)
    Foo,
}

todavía no se compila - el atributo en (2) produce el error: macro `error_chain` may not be used in attributes porque la macro macro_rules aparentemente entra en conflicto con el atributo registrado por la derivación personalizada en lugar de ser anulado como en el primer caso.

Así que tengo que cambiar el nombre tanto de la derivación personalizada como de su atributo. El atributo se usa mucho más (uno en cada variante de la enumeración) que la derivación personalizada (una en cada enumeración), por lo que este es un cambio de ruptura más grande de lo que esperaba. Entiendo que esta es una situación complicada de mi propia construcción (reutilizando el nombre de la macro macro_rules para una derivación personalizada y su atributo), pero este también es un código que se ha estado compilando en estable desde que las derivaciones personalizadas fueron estabilizado, por lo que no tenía ninguna razón para pensar que sería un problema seis meses después.

¿Se puede tal vez hacer que los atributos de las derivaciones personalizadas anulen las macros macro_rules al igual que las derivaciones personalizadas anulan las macros macro_rules ? En realidad, no veo cómo podría haber alguna ambigüedad entre ellos, pero supongo que es la misma razón que cuando se importa una macro macro_rules después de una derivación personalizada del mismo nombre, que todas las macros se colocan en el mismo espacio de nombres sin considerar qué tipo de macro son.

¿Hay algún "lugar" menos formal para hablar sobre las macros proc? ¿Te gusta un canal de IRC #rust-proc-macro ? Me encantaría hacer pequeñas preguntas sobre la función de vez en cuando, pero se siente mal enviar spam a este hilo: see_no_evil: Y en el canal #rust , la mayoría de la gente no ha trabajado con proc-macros y especialmente la nueva proc_macro API (ya que es inestable y todo). Entonces, ¿alguna idea de dónde discutir este tema?

@LukasKalbertodt #rust-internals , tal vez, o simplemente inicie un nuevo hilo en / r / rust.

TokenStream::from_str entra en pánico cuando se usa fuera de una macro de procedimiento (por ejemplo, en un script de compilación):

thread 'main' panicked at 'proc_macro::__internal::with_sess() called before set_parse_sess()!', /checkout/src/libproc_macro/lib.rs:758:8

¿Sería posible / deseable reemplazar este pánico con la creación implícita de una "sesión" ficticia? ¿O quizás agregar una API pública (con una ruta de estabilización) para crear una?

¿Alguien ha mirado literatura sobre macros de otros sistemas? Me gustaría escuchar la opinión de la gente sobre esto. Hablaré sobre Scheme aquí, ya que eso es con lo que estoy más familiarizado.

Personalmente, estoy trabajando en la implementación de syntax-rules para el esquema R7RS en mi propio proyecto, y he descubierto que syntax-case puede formar la base para admitir sistemas macro tanto antihigiénicos como higiénicos ( defmacro y syntax-rules ). GNU Guile hace esto. syntax-case también tiene soporte para guardabarros que pueden realizar una validación de predicado adicional en listas de objetos de sintaxis (o algo entre las líneas de TokenStream en Scheme). Puedo ver que se está trabajando en Mark , y parece que está inspirado en Bindings as Sets of Scopes .

Además, ¿deberíamos también discutir si se debe admitir el cálculo arbitrario en tiempo de compilación? Racket en realidad toma un enfoque completo de "fase" de las cosas, parece, con begin-for-syntax permitiendo definiciones y cálculos (?) En el nivel de tiempo de compilación durante la expansión macro. .

El control sobre la higiene es muy posible con (datum->syntax <thing-to-copy-scope-from> <thing-to-apply-scope-to>) en Scheme, lo que le permite escapar del alcance de una macro y, en su lugar, asumir el alcance de un objeto fuera del alcance inmediato.

Tome este ejemplo de The Scheme Programming Language, 3ª ed. por R. Kent Dybvig (Chez Scheme, ahora en Cisco Systems): http://www.scheme.com/tspl3/syntax.html . El ejemplo muestra (include "filename.scm") como una macro syntax-case y permite que el intérprete utilice una macro para configurar el tiempo de ejecución para leer un archivo y continuar la evaluación. La pregunta más profunda aquí es si queremos que un sistema macro-macro permita que sucedan tales cosas en el tiempo de la macroexpansión y active cálculos en tiempo de compilación, como activar la importación de un archivo (aunque esto parece ocurrir en la funcionalidad del compilador directo, así que tal vez no queramos hacer esto).

¿Cuáles deberían ser los límites de las macros? Me imagino que Rust, queriendo reducir su tiempo de compilación, quiere restringir la evaluación en tiempo de compilación (y especialmente evitar bucles infinitos). Racket ha adoptado el enfoque de "torre de preparadores y expansores" con fases como se indica en Lisp in Small Pieces. ¿Queremos permitir cosas como permitir el acceso a una API en tiempo de compilación para realizar E / S de archivos y cálculo recursivo limitado? ¿Deberíamos permitir que las macros de procedimiento puedan convertir las especificaciones de la hoja de cálculo CSV en declaraciones de cambio?

¡Me encantaría conocer otros sistemas! Escuché que Template Haskell tiene un enfoque interesante con tipos bien definidos para representar su AST, y la pereza en Haskell puede reemplazar muchos usos de macros para estructuras de control.

Lo siento si me salgo de la línea.

¿Cuáles deberían ser los límites de las macros?

Para macros de procedimiento , que se tratan en este número, ninguno . Una macro de procedimiento es una extensión del compilador. Puede tomar un poco de código C ++, ejecutarlo mediante clang y agregar el objeto resultante a la compilación. Puede tomar algo de SQL, consultar la base de datos para encontrar el tipo de resultado correspondiente y generar el conjunto de resultados apropiado. ¡Esos son casos de uso reales que la gente quiere hacer!

Tenga en cuenta que Rust tiene otro sistema de macros. Su actualización fue aprobada como RFC 1584 y https://github.com/rust-lang/rust/issues/39412 realiza un seguimiento de la implementación

@VermillionAzure , de un vistazo rápido a los formularios de Scheme a los que hizo referencia:

El macro_rules , y su actualización por RFC 1584 , es similar a syntax-rules . Si tiene sugerencias para mejorarlas, https://github.com/rust-lang/rust/issues/39412 es probablemente el mejor lugar para discutir eso.

Las macros proc, sobre las que trata este problema, son como la forma general de define-syntax . Y este RFC ( 1566 ) muy intencionalmente no define nada como syntax-case . Solo una interfaz para llamar a una función para transformar el flujo de tokens.

La interfaz está definida de tal manera que algo como syntax-case se puede implementar en una caja separada (biblioteca) y la intención es hacerlo de esa manera. Si lo desea, no dude en jugar. Tanto cualquier prototipo como un informe sobre lo fácil o difícil de usar de la API serán ciertamente bienvenidos.

Creo que la idea era definir macros como funciones, como en lisp, pero tener una macro, que devuelve la macro, que macro_rules! define.

Entonces lo siguiente sería equivalente:

    macro_rules! foo {/*define macro here*/}
#[proc_macro]
pub fn foo(tokens: TokenStream) -> TokenStream {
    macro_case! tokens {/*define macro here*/} //takes `tokens` as first argument, returns a `TokenStream`
}

Así es como parecen funcionar en el esquema syntax-rules y syntax-case .

@VermillionAzure
¿Es esto lo que te gustaría?

@ porky11 No, no lo parece. Solo quería ver si las macros de Scheme serían una idea relevante para agregar a la discusión; es obvio que, dado que las macros de procedimiento están destinadas a ser mucho más poderosas que el sistema de macros syntax-case en Scheme, es trivial para implementar todos los sistemas macro en términos del poder arbitrario proporcionado aquí.

@ jan-hudec ¿Es prudente permitir cualquier cálculo arbitrario como extensión del compilador sin ningún tipo de garantía de seguridad? Estoy absolutamente anonadado por la idea de que las macros de procedimiento van a ser tan poderosas aquí, pero ¿algún usuario potencial de Rust consideraría esto una desventaja del uso de paquetes? No soy un experto en seguridad de ninguna manera, pero ¿las vulnerabilidades en las bibliotecas que se usan dentro de las extensiones del compilador no podrían usarse fácilmente para convertir maliciosamente el compilador Rust en un vector de ataque? Además, si se produce algún error en las bibliotecas utilizadas en macros de procedimiento (por ejemplo, segfault desencadenado por un código de biblioteca C incorrecto), ¿significa esto que el segfault se filtraría y haría que el compilador fallara sin los mensajes de error adecuados?

¿Habría alguna forma de encapsular los errores que ocurren en las macros de procedimiento de manera que no afecten a ninguna otra parte del compilador?

Otra idea: ¿cuándo se ejecutan las macros de procedimiento? Si las macros de procedimiento pueden interactuar con el código que tiene efectos secundarios que podrían ser relevantes (por ejemplo, comunicarse con un servidor externo con estado, mutar una base de datos SQL externa, obtener una clave de seguridad para iniciar sesión en un sistema externo), entonces eso no significa que el ¿Es importante el orden en el que se activan las macros de procedimiento mediante el proceso de compilación?

Los paquetes de @VermillionAzure Cargo ya pueden tener scripts de compilación que ejecutan código arbitrario en tiempo de compilación, por lo que las macros de procedimiento no empeoran las cosas en ese frente: ya necesita confiar en sus dependencias. (Esto se hace algo más fácil porque crates.io es inmutable / solo para agregar, y las dependencias no se actualizan automáticamente si tiene un archivo Cargo.lock : solo necesita confiar en versiones específicas). E incluso si los scripts de compilación no lo hicieron existen, sus dependencias aún pueden por naturaleza ejecutar código arbitrario en tiempo de ejecución. ¿El tiempo de compilación es mucho peor?

Esta discusión me hace pensar en un problema relacionado, pero diferente.

Suponga que una caja define dos macros de proceso: foo!() escribe un archivo temporal y bar!() lee ese mismo archivo. Un consumidor de esta caja invoca tanto foo!() como bar!() en el mismo módulo. Entonces, si la compilación tiene éxito o no dependerá de cuál de foo!() o bar!() se expanda primero. Este orden está definido por la implementación, y si suficientes personas escriben código como este, puede convertirse en estándar de facto.

Sin embargo, no estoy seguro de qué tan problemático es esto. Solo me preocupa si esto conducirá a una repetición del campo de estructura ordenando travesuras.

@SimonSapin

Si bien estoy de acuerdo con su posición, debo señalar que hay una diferencia significativa entre la ejecución en tiempo de compilación y la ejecución en tiempo de ejecución:

Proporciona un modelo de amenaza diferente, ya que las cosas tienden a compilarse una vez y luego implementarse en muchas máquinas. (Por ejemplo, explotar la falta de atención del mantenedor más una deficiencia de espacio aislado en un clúster de compilación de distribución de Linux).

@lfairy Sí, este es exactamente el problema que tuvo Racket hace más de una década en 2002. Matthew Flatt, el mayor contribuyente de Racket, creó un artículo llamado "Macros compilables y compilables: ¿lo quieres cuando?. R. Kent Dybvig, que trabajó en Chez Scheme, también escribió un artículo sobre las fases en la evaluación de bibliotecas / módulos en "Implicit Phasing in R6RS Libraries" .

@SimonSapin El tiempo de compilación puede ser mucho peor. Si su compilador falla al azar o realiza un comportamiento malicioso que es activado por el compilador, entonces apostaría a que alguien terminaría escribiendo una publicación enorme de Reddit que se titularía "Los módulos de Rust son intrínsecamente inseguros" o algo así.

@VermillionAzure , no leí los artículos con mucho cuidado, pero no creo que sean relevantes para la discusión, ya que los problemas que enfrenta Rust son muy diferentes de los que enfrenta Scheme.

En Scheme, una biblioteca puede proporcionar tanto funciones como macros, por lo que el compilador debe clasificar correctamente qué funciones necesita en tiempo de compilación y cuáles necesita en tiempo de ejecución. Sin embargo, en Rust, una caja proporciona macros de procedimiento o funciones de tiempo de ejecución, por lo que esta división es (por el momento) obvia.

(Tenga en cuenta que una caja que proporciona funciones de tiempo de ejecución también puede proporcionar macros basadas en reglas (higiénicas), pero esos son mecanismos separados en Rust)

El problema del que habla @lfairy es el de ordenar la ejecución de las funciones de expansión. En Rust, la compilación puede ser paralela para archivos separados y puede ser incremental, por lo que el orden de ejecución de los expansores no está definido. Pero, ¿alguno de los artículos aborda realmente eso? Yo no lo vi.

@ jan-hudec Sí, supongo que tienes razón. Pero el orden de evaluación definitivamente importará si se permiten efectos secundarios en tiempo de compilación, a menos que pueda garantizar que cierto módulo no produce efectos secundarios. ¿Se puede escribir un módulo?

Creo que una macro de procedimiento "probablemente no debería" tener efectos secundarios porque no se puede confiar en algunos detalles (ver más abajo), pero es probable que no tengamos un mecanismo similar a un sistema de tipos en el lenguaje para forzarlos a ser puramente funcional.

Estos detalles incluyen el orden de ejecución y la simultaneidad en comparación con otras macros proc, y si una macro proc se vuelve a ejecutar en una compilación incremental. Para este último, es posible que deseemos agregar algo para declarar dependencias similares a rerun-if-changed en los scripts de compilación. Y al igual que el script de compilación, estas declaraciones pueden estar incompletas o con errores. No podemos prevenir estáticamente todos los errores.

Creo que deberíamos evitar garantizar nada sobre los efectos secundarios (es decir, las cajas de macro proc no pueden depender del funcionamiento de los efectos secundarios, ni pueden depender de que se vuelvan a activar para otra cosa que no sea un cambio de código en el módulo en el que se aplican ( entonces, no hay estado global).

Más tarde, podemos relajar este requisito con una forma de especificar rerun-if-changes y otras cosas.

(Tengo una propuesta de seguridad macro de secuencia de comandos / proceso de compilación general a medio hacer que ayudará un poco aquí, pero todavía no la he escrito)

Las macros proc de la OMI / derivación personalizada deben colocarse en un entorno de espacio aislado sin ninguna E / S u otra conexión con el exterior y ser evaluadas por miri, tal vez con un JIT de cranelift.

@ est31 esa es una buena idea, pero cosas como diesel infer_schema! ya
existe, bindgen necesita leer archivos y ejecutar programas, ¡incluso incluir! y
env! utilizar E / S.

El 9 de noviembre de 2017 a las 06:19, "est31" [email protected] escribió:

Las macros proc de OMI / derivación personalizada deben colocarse en un entorno de espacio aislado
sin ninguna E / S u otra conexión al exterior y ser evaluado por
miri, tal vez con un cranelift JIT.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/rust-lang/rust/issues/38356#issuecomment-343124957 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAC3n5VOPdKBsu81Sp3tp2XlIQ05L865ks5s0t_PgaJpZM4LMWlc
.

Parece que # 40939 y # 44528 ya se han fusionado ... @jseyfried, ¿ podrías actualizar la lista de verificación?

@ mark-im actualizado.

¿Pueden las macros de procedimiento generar macros de procedimiento?

@VermillionAzure No lo he probado, pero no veo una razón por la que no puedan. Si, por supuesto, como las macros proc que generan código en "tiempo de ejecución", deberían estar en cajas separadas de aquellas en las que se utilizan.

En sincronía, nos encontramos con una limitación de proc_macro :: TokenNode hoy: los delimitadores de bloque { ... } están asociados con un solo Span en el TokenStream de entrada, por lo que no hay forma de activar un error que apunta solo al cierre } . Rustc no parece tener esta limitación.

mod m {
    type T =
}
error: expected type, found `}`
 --> src/main.rs:3:1
  |
3 | }
  | ^

Las mejores cosas que podemos hacer en una macro proc son apuntar al último token dentro del bloque, apuntar a todo el bloque o apuntar al siguiente token después del bloque, nada de lo cual es realmente lo que desea para un error como el anterior.

Una solución general sería hacer que Span::start y Span::end devuelvan un Span lugar de un LineColumn como lo hacen actualmente, y luego exponer una forma de vaya desde Span a la primera línea / columna del intervalo.

sp.begin().line // before
sp.line() // after

sp.end().line // before
sp.end().line() // after

sp.end() // after, not possible before

Mencionando a @abonander, quien agregó esa API en # 43604.

hacer que Span :: start y Span :: end devuelvan un Span de 1 carácter en lugar de LineColumn como lo hacen actualmente, luego exponga una forma de ir desde Span hasta la primera línea / columna de span.

Eso haría que Span adoptara el comportamiento especial que necesitan las listas delimitadas, pero sería incorrecto para todos los demás intervalos. Generalmente no es correcto. Considere obtener un intervalo para una expresión como foo(hi) uniendo cosas. Ahora desea apuntar al foo y tomar sp.begin() , pero sp.begin() solo apunta al primer carácter de foo .

Creo que las mejores soluciones serían agregar dos tramos a proc_macro::TokenNode::Group o permitir la creación de tramos arbitrarios.

Span::begin embargo, es posible que los tipos de devolución de end tengan que cambiar: https://github.com/rust-lang/rust/pull/43604#issuecomment -327643229

Estoy tratando de obtener Span::def_site() para resolver las cosas en relación con lo que está dentro del alcance de mi macro de procedimiento. ¿Estoy entendiendo mal cómo se supone que funciona esto?

Casi el mismo código funciona si uso Span::call_site() y tengo MySend definido en main.rs, que es lo que esperaría. Sin embargo, no he podido hacerlo funcionar con def_site() .

#![feature(proc_macro)]

extern crate proc_macro;

use std::marker::Send as MySend;
use proc_macro::{TokenStream, TokenTree, TokenNode, Term, Delimiter, Span};

#[proc_macro]
pub fn impl_mysend_for(tokens: TokenStream) -> TokenStream {
    let span = Span::def_site();
    let ident = tokens.into_iter().next().unwrap();
    vec![
        TokenTree { span, kind: TokenNode::Term(Term::intern("unsafe")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("impl")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("MySend")) },
        TokenTree { span, kind: TokenNode::Term(Term::intern("for")) },
        ident,
        TokenTree { span, kind: TokenNode::Group(Delimiter::Brace, TokenStream::empty()) }
    ].into_iter().collect()
}
#![feature(proc_macro)]

extern crate mac;

struct S;
mac::impl_mysend_for!(S);

fn main() {}
error[E0405]: cannot find trait `MySend` in this scope
 --> src/main.rs:6:1
  |
6 | mac::impl_mysend_for!(S);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `Send`?

Rastreando esto en el lado Syn: https://github.com/dtolnay/syn/issues/290.

@dtolnay
El problema aquí es que MySend se importa en la fase 0 (es decir, para la arquitectura del host cuando se realiza una compilación cruzada), por lo que no está disponible en la fase 1 (es decir, cuando se compila para la arquitectura de destino).

La solución aquí es permitir que las cajas proc-macro tengan dependencias de la fase 1 (arquitectura de destino) para que podamos importar elementos de la fase 1 al alcance.

Hoy, una solución alternativa es volver:

quote! { // n.b. non-interpolated tokens from `quote!` have `Span::def_site()`
    mod dummy {
        extern crate std;
        use self::std::marker::Send as MySend;
        unsafe impl MySend for $ident {} // this line is equivalent to what you have above
    }
} 

También puede construir esto manualmente, solo estoy usando quote! por conveniencia.

Debido a la higiene, dummy / std / MySend nunca chocará con nada más dentro del alcance, por lo que, por ejemplo, es seguro usar esta macro más de una vez en el mismo módulo, es seguro que ident sea ​​"MySend", etc.

Este problema, así como la necesidad y la solución al mod dummy , se describe con más detalle en https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Lamentablemente, hasta que se implementen las dependencias de la fase 1, esto no será ergonómico.

¡Gracias @jseyfried! Eso funciona. Algunas preguntas de seguimiento:

  • En el código de mi comentario anterior, si cambio impl_mysend_for para generar un impl para Send lugar de MySend entonces todo se compila. ¿A qué Send se está resolviendo y por qué no llega a la distinción entre la fase 0 y la fase 1? ¿Está funcionando intencionalmente o por accidente?

  • ¿Qué más hay en el alcance que puedan usar mis def_site() tokens, como Send ?

  • Si MySend necesita provenir de una biblioteca (como imaginar que estamos derivando serde::Serialize ), entonces el usuario final todavía necesita serde en su Cargo.toml, incluso si no lo hacemos Necesito que escriban extern crate serde . ¿Sería posible hacer extern crate con una resolución def_site() ident contra la macro de procedimiento Cargo.toml, y extern crate con una resolución call_site() ident contra la corriente descendente? Cargo.toml?

Para las cajas externas, supongo que las cajas deberían estar disponibles explícitamente para la fase 1 mediante la macro proc.

#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

@dtolnay

En el código de mi comentario anterior, si cambio impl_mysend_for para generar una impl para Enviar en lugar de MySend, todo se compila. ¿A qué envío se está resolviendo y por qué no llega a la distinción entre la fase 0 y la fase 1? ¿Está funcionando intencionalmente o por accidente?

Buena pregunta. En este momento, el preludio está dentro del alcance en el sitio de definición (a menos que la caja proc-macro sea #![no_implicit_prelude] ) y esto es un accidente (en cierto sentido) debido a la distinción entre la fase 0 y la fase 1, como señala .

Sin embargo, para la ergonomía, creo que la fase 1 debería contener implícitamente std en la raíz proc-macro (para que siempre pueda quote!(use std::...); ) y el preludio por conveniencia / ergonomía y dado que estos ya están implícitos en la fase 0. Habrá un PR para agregar std en la raíz en la fase 1 pronto.

¿Qué más hay en el alcance que pueden usar mis tokens def_site (), como Enviar?

Además del preludio y (pronto) std como se discutió anteriormente, las únicas otras cosas en el alcance en la fase 1 son las propias macros proc (no las funciones proc-macro, que son la fase 0).

Por ejemplo,

#[proc_macro]
fn f(input: TokenStream) -> TokenStream { ... }

#[proc_macro]
fn g(_input: TokenStream) -> TokenStream {
    quote! {
        f!(); ::f!(); // These both resolve to the above proc macro
        f(); // This doesn't resolve since the function is in phase 0
    }
}

¿Sería posible hacer una caja externa con una resolución def_site () ident contra el Cargo.toml de la macro de procedimiento, y una caja externa con una resolución call_site () ident contra el Cargo.toml descendente?

Sí, excepto que creo que una caja externa con Span::def_site() debería resolverse contra las dependencias de la fase 1 (objetivo) de la macro de procedimiento Cargo.toml ; las dependencias de la fase 0 de hoy están vinculadas a bibliotecas compiladas para la plataforma host . Dado que las dependencias de la fase 1 aún no existen, el nombre de la caja externa se resuelve de manera antihigiénica, lo cual es molesto, como señaló.

Una vez que tengamos las dependencias de la fase 1, no necesitaremos citar extern crate s en cada expansión para empezar, por lo que esto será un problema menor. Sin embargo, aún debemos solucionarlo: el plan actual es intentar resolver primero las dependencias de destino de la caja proc-macro y luego volver a la resolución antihigiénica con un ciclo de advertencia de baja prioridad para evitar la rotación.

Para las cajas externas, supongo que las cajas deberían estar disponibles explícitamente para la fase 1 mediante la macro proc.
#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

Interesante, podríamos implementarlo de esta manera.

En cambio, estaba pensando que la caja de la fase 1 se declararía en la raíz de la caja proc-macro (por ejemplo, #[phase(1)] extern crate foo; ) para que estuviera disponible automáticamente en todas las macros de proc (por ejemplo, quote!(use foo::bar); ). Dado que extern crate está saliendo de todos modos, podríamos evitar declarar las cajas de la fase 1 por completo: todas las dependencias de destino del Cargo.toml estarían automáticamente dentro del alcance en la raíz de la caja proc-macro en la fase 1.

En mi código, descubrí que parece que estoy usando intervalos para dos propósitos: controlar la resolución de nombres y controlar los mensajes de error. ¿Están estos dos vinculados inseparablemente, o sería posible hacer un tramo que mezcle el aspecto de resolución de nombres de un tramo con las ubicaciones de mensajes de error de línea / columna de un tramo diferente? Espero que esta sea una necesidad común.

Para ser más específico, tengo un rasgo dentro del alcance dentro del def_site de mi derivado personalizado y quiero invocar métodos de rasgo en los campos de la estructura del usuario. Si el tipo de campo no implementa el rasgo correcto, quiero que el mensaje de error subraye el campo de estructura correspondiente.

Puedo generar la llamada al método con un intervalo def_site que se compila y se ejecuta, pero los mensajes de error lamentablemente siempre apuntan al atributo derivar como vimos con Macros 1.1.

  |
4 | #[derive(HeapSize)]
  |          ^^^^^^^^

O puedo generar la llamada al método con el mismo intervalo que el identificador o tipo del campo de estructura, que muestra los subrayados correctos pero no se resuelve en el rasgo en el alcance en mi def_site.

  |
7 |     bad: std::thread::Thread,
  |     ^^^^^^^^^^^^^^^^^^^^^^^^

¿Cómo puedo resolver correctamente y mostrar los errores de la forma que quiero?

@dtolnay Ese es un excelente punto, gracias.

Creo que la forma correcta de arreglar https://github.com/rust-lang/rust/issues/46489 podría ser hacer que los tokens #[derive(…)] generados tengan intervalos de resolución de nombres en el mismo scope como la definición de tipo, y error-messages-se extiende en la invocación de macro quote! {} que los creó.

¿Cuál es la historia de la higiene actualmente? Tengo una función como macro de procedimiento que solía funcionar (hace 4 meses) pero a partir de rustc 1.24.0-nightly (b65f0bedd 2018-01-01) se queja de que el argumento no se puede encontrar en el alcance.

Lo siento, debería haber buscado en el rastreador de problemas primero, parece que acabo de presionar https://github.com/rust-lang/rust/issues/46489.

Presenté # 47311 que creo que actualmente bloquea una implementación correcta de derivar (Deserialize). Las macros de procedimiento no pueden construir una estructura que tenga campos privados.

Archivado otro, # 47312 en el que el acceso a un campo de estructura de tupla sin nombre como self.0 tiene requisitos diferentes en el intervalo del token . que el acceso a un campo de estructura con nombre como self.x .

47311 y # 47312 están arreglados en # 48082 y # 48083, respectivamente.

Tengo los dos RP anteriores esperando revisión / comentario.

Ese RP fue abandonado pero revivido y se sigue trabajando en # 48465. Actualmente esperando en Crater.

@petrochenkov @nrc

Mirando syntax::ext::expand , parece que proc_macro_attribute s actualmente no se están procesando en varios contextos (no exhaustivo):

  • en bloques ( fold_block() es un noop)
  • sobre declaraciones / expresiones (# 41475, # 43988)
  • dentro de extern {} bloques (# 48747)

RFC 1566 no enumera tipos de nodos AST específicos a los que se pueden aplicar macros de atributos, lo que sugiere que deberían ser aplicables a casi cualquier cosa. Pero eso podría volverse un poco ridículo, por lo que deberíamos establecer claramente qué es necesario procesar pero no, y dónde los atributos nunca deberían estar permitidos pero podrían estarlo actualmente (# 43988)

@abonander, la intención es que los atributos de macro proc se puedan usar en cualquier lugar donde pueda estar un atributo regular y en ningún otro lugar, lo que creo que cubre todo lo anterior (aunque algunos no son estables, y si estabilizamos las macros proc, debemos tener cuidado de estabilizar únicamente usos que sean estables para otros atributos).

@nrc existe en la referencia solo dice que los atributos se pueden aplicar a cualquier elemento . Sin embargo, estoy casi seguro de que los atributos de lint también se pueden aplicar a bloques y declaraciones.

@nrc existe en

No hay afaik: hay un RFC aceptado y un indicador de característica inestable para atributos en cualquier expresión, pero creo que solo nos hemos estabilizado en declaraciones y bloques. La referencia no tiene datos.

Este problema:

Macros de comprobación de estabilidad (proc-) (número 34079).

Ahora está cerrado WRT proc-macros. Mi PR simplemente no agregó la verificación de estabilidad para las macros Macros 2.0, razón por la cual el problema aún está abierto (aunque probablemente debería ser un problema nuevo en su lugar).

@rfcbot fcp fusionar

Me gustaría proponer que un subconjunto de macros 2.0 se estabilice como macros 1.2 para la versión Rust 1.28. Rust 1.28 ingresa todas las noches el 10 de mayo de 2018 (~ 2.5 semanas después de escribir esto) y se estabilizará el 2 de agosto de 2018. Creo que FCP puede terminar antes del límite del 10 de mayo para que 1.27 ingrese a la versión beta, pero me gustaría esperar apague cualquier estabilización aquí hasta después de que haya ocurrido ese corte y retrase esto hasta el lanzamiento de 1.28.

Esto se ha debatido en los aspectos @petrochenkov y que deberían solucionarse ahora (pero aún no se han publicado todas las noches). Creo que sería útil recapitular aquí para que este sea concretamente el subconjunto que se estabilizaría.

Sin embargo, recuerde que este es un subconjunto . La funcionalidad que falta aquí no significa que nunca se estabilizará o eliminará del compilador. Más bien, esta funcionalidad permanecerá inestable después de este pase de estabilización propuesto para estabilizarse en una fecha posterior.

Macros y el sistema de módulos

Cubierto principalmente por https://github.com/rust-lang/rust/issues/35896 y ahora
habiendo terminado su FCP, la idea principal es que puede usar use declaraciones para
importar macros. Por ejemplo, código como este:

use some_proc_macro_crate::bar;

#[bar]
fn baz() {}

o

use some_proc_macro_crate::bar;
bar!();

o incluso

pub use some_proc_macro_crate::bar; // reexport an attribute or macro

Esto introduce un tercer espacio de nombres en Rust (además del valor / tipo
espacios de nombres), el espacio de nombres macro. Atributos, macro_reglas y procedimientos
todas las macros residen en el espacio de nombres maro.

La diferencia con el sistema de módulos completo es que solo un elemento Se permitirá que las rutas invoquenmacros .
Por ejemplo, #[foo::bar] o ::bar::baz!() no se permitirán. Esta
La restricción puede levantarse algún día, pero esta es una buena ruta conservadora para
Empezar con.

¿Dónde puede ocurrir la expansión?

Los atributos solo se pueden aplicar a los que no son móduloselementos .
"elementos" aquí incluye elementos como elementos de rasgo, elementos implícitos y módulo externo
elementos. La expansión del módulo aún no será estable debido a la higiene y
ramificaciones de la implementación. Queda por especificar y estabilizar esto en un
fecha posterior.

Las macros de atributos de expresión y declaraciones aún no serán estables. Este es
principalmente debido a la necesidad real de higiene a nivel de expresión (como
opuesto al nivel de artículo). Esto se deja estabilizar en una fecha posterior.

Finalmente, las macros de atributos deben tener argumentos dentrodelimitadores .
Por ejemplo #[foo] , #[foo(bar)] y #[foo { bar baz ... @ | ^ hello }]
son invocaciones válidas. Invocaciones como #[foo = "baz"] , #[foo bar] o
#[foo ... = ( baz )] no será inicialmente estable.

¿Qué aspecto tienen las macros de procedimiento?

Al igual que la derivación personalizada, se definen en cajas tipo caja proc-macro .
Los atributos y macros de procedimiento se definen así:

extern crate proc_macro;
use proc_macro::TokenStream;

/// Invoked as `foo!()`
///
/// When invoked as `foo!(a b ( c ))` then the `TokenStream`
/// here will be `a b ( c )`.
///
/// The invocation is replaced with the `TokenStream` returned
#[proc_macro]
pub fn foo(a: TokenStream) -> TokenStream {
    // ...
}

/// Invoked as `#[bar]`
///
/// The first argument, `attr`, is the token stream inside of the attribute
/// itself. The second argument, `item`, is the token stream corresponding to
/// the item the attribute is attached to.
///
/// An attribute of the form `#[bar ( a b [ c ] )]` will have the `attr`
/// argument look like `a b [ c ]`. Note the lack of delimiters passed to
/// `attr`! An API may later be added to learn what delimiter a macro was
/// invoked with.
///
/// The `item` here is a tokenified version of the original item.
///
/// The return value here will contain all non-expanded attributes as well for
/// this attribute to inspect. The return value replaces the original item.
#[proc_macro]
pub fn bar(attr: TokenStream, item: TokenStream) -> TokenStream {
    // ...
}

¿Y la higiene?

Arriba se vio que los atributos personalizados y las macros solo se pueden expandir en
contextos de elementos , en particular, solo generar nuevos nodos AST que son elementos. Esta
significa que solo tenemos que preocuparnos por la higiene de generar un nuevo artículo AST
nodos.

Los artículos nuevos tendrán la misma higiene que macro_rules! hoy. Lo harán
no ser higiénico. Los elementos nuevos agregados al AST ingresarán al mismo espacio de nombres que
otros elementos del módulo.

La API proc_macro .

Para posibilitar todo esto se estabilizará la siguiente superficie para
la caja proc_macro :

pub struct TokenStream(_);

impl TokenStream {
    pub fn empty() -> TokenStream;
    pub fn is_empty(&self) -> bool;
}

impl Clone for TokenStream { ... }
impl Debug for TokenStream { ... }
impl Display for TokenStream { ... }
impl FromStr for TokenStream { ... }
impl From<TokenTree> for TokenStream { ... }
impl FromIterator<TokenTree> for TokenStream { ... }
impl FromIterator<TokenStream> for TokenStream { ... }
impl !Send for TokenStream { ... }
impl !Sync for TokenStream { ... }

impl IntoIterator for TokenStream {
    type Item = TokenTree;
    type Iter = token_stream::IntoIter;
}

pub mod token_stream {
    pub struct IntoIter(_);

    impl Iterator for IntoIter {
        type Item = ::TokenTree;
    }
}

pub enum TokenTree {
    Op(Op),
    Term(Term),
    Literal(Literal),
    Group(Group),
}

impl TokenTree {
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Clone for TokenTree { ... }
impl Debug for TokenTree { ... }
impl Display for TokenTree { ... }
impl From<Op> for TokenTree { ... }
impl From<Term> for TokenTree { ... }
impl From<Literal> for TokenTree { ... }
impl From<Group> for TokenTree { ... }
impl !Send for TokenTree { ... }
impl !Sync for TokenTree { ... }

pub struct Span(_);

impl Span {
    pub fn call_site() -> Span;
}

impl Clone for Span { ... }
impl Copy for Span { ... }
impl Debug for Span { ... }
impl !Send for Span { ... }
impl !Sync for Span { ... }

pub struct Group(_);

pub enum Delimiter {
    Parenthesis,
    Brace,
    Bracket,
    None,
}

impl Group {
    pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group;
    pub fn stream(&self) -> TokenStream;
    pub fn delimiter(&self) -> Delimiter;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Clone for Group { ... }
impl Debug for Group { ... }
impl Display for Group { ... }
impl !Send for Group { ... }
impl !Sync for Group { ... }

impl Copy for Delimiter { ... }
impl Clone for Delimiter { ... }
impl Debug for Delimiter { ... }
impl PartialEq for Delimiter { ... }
impl Eq for Delimeter { ... }

pub struct Term(_);

impl Term {
    pub fn new(s: &str, span: Span) -> Term;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Copy for Term { ... }
impl Clone for Term { ... }
impl Debug for Term { ... }
impl Display for Term { ... }
impl !Send for Term { ... }
impl !Sync for Term { ... }

pub struct Op(_);

pub enum Spacing {
   Alone,
   Joint,
}

impl Op {
    pub fn new(op: char, spacing: Spacing) -> Op;
    pub fn op(&self) -> char;
    pub fn spacing(&self) -> Spacing;
    pub fn span(&self) -> Span;
    pub fn set_span(&mut self, span: Span);
}

impl Debug for Op { ... }
impl Display for Op { ... }
impl Clone for Op { ... }
impl Copy for Op { ... }
impl !Send for Op { ... }
impl !Sync for Op { ... }

impl Copy for Spacing { ... }
impl Clone for Spacing { ... }
impl Debug for Spacing { ... }
impl PartialEq for Spacing { ... }
impl Eq for Spacing { ... }

pub struct Literal(_);

impl Literal {
  // panic on infinity and NaN
  pub fn f{32,64}_{un,}suffixed(f: f{32,64}) -> Literal;

  pub fn i{8,16,32,64,128,size}_{un,}suffixed(n: i{8,16,32,64,128,size}) -> Literal;
  pub fn u{8,16,32,64,128,size}_{un,}suffixed(n: u{8,16,32,64,128,size}) -> Literal;

  pub fn string(s: &str) -> Literal;
  pub fn character(c: char) -> Literal;
  pub fn byte_string(b: &[u8]) -> Literal;

  pub fn span(&self) -> Span;
  pub fn set_span(&mut self, span: Span) -> Span;
}

impl Clone for Literal { ... }
impl Debug for Literal { ... }
impl Display for Literal { ... }
impl !Send for Literal { ... }
impl !Sync for Literal { ... }

Puede encontrar más información sobre esta API en original. PR

Estrategia de prueba

Los sistemas macros 1.1 y macros 2.0 han sido ampliamente controlados a lo largo de
el ecosistema desde hace bastante tiempo. En particular, toda esta propuesta también
ampliamente probado a través de la versión 0.3 de la caja proc-macro2 como
así como la caja syn . A lo largo de las pruebas, se han detectado varios errores
identificado y fijo y el sistema actual se siente lo suficientemente sólido como para comenzar a
estabilizado. (¡por no decir que está libre de errores!)

El miembro del equipo @alexcrichton ha propuesto fusionar esto. El siguiente paso es la revisión por parte del resto de equipos etiquetados:

  • [x] @Kimundi
  • [] @SimonSapin
  • [x] @alexcrichton
  • [x] @aturon
  • [x] @cramertj
  • [x] @dtolnay
  • [x] @eddyb
  • [x] @joshtriplett
  • [x] @nikomatsakis
  • [x] @nrc
  • [] @pnkfelix
  • [x] @scottmcm
  • [x] @sfackler
  • [x] @withoutboats

No hay preocupaciones actualmente enumeradas.

Una vez que la mayoría de los revisores aprueben (y ninguno objete), entrará en su período de comentarios final. Si detecta un problema importante que no se ha planteado en ningún momento de este proceso, ¡hable!

Consulte este documento para obtener información sobre los comandos que pueden darme los miembros del equipo etiquetados.

cc @ rust-lang / compiler, todos ustedes que conozco también están muy interesados ​​en esto y no dude en plantear cualquier objeción. Si tiene una objeción de bloqueo, también puedo registrarla por usted

Parece que, utilizando la API provista propuesta para la estabilización, las macros proc pueden generar fácilmente todo tipo de tokens o copiarlos de entrada a salida, pero no pueden inspeccionar fácilmente un flujo de tokens ni siquiera a un nivel superficial. Por ejemplo, Literal no implementa Eq o PartialEq . ¿Alguna razón en particular para eso? (E incluso eso solo permitiría la comparación con valores constantes especificados, en lugar de extraer un valor y procesarlo en código).

Dentro de una implementación de macro proc, dado un TokenStream , ¿qué puede hacer una macro proc para introspectar un literal? ¿O, para el caso, extraer el valor de uno? ¿Esto simplemente no es compatible todavía? ¿Existe un plan para apoyarlo en el futuro?

(No estoy intentando bloquear la estabilización del subconjunto propuesto; solo me gustaría comprender mejor ese subconjunto y sus características previstas).

@alexcrichton ¡ Los artículos nuevos tendrán la misma higiene que las macro_rules! hace hoy. Lo harán
no ser higiénico. Los elementos nuevos agregados al AST ingresarán al mismo espacio de nombres que
otros elementos del módulo.

No estoy en el equipo central de Rust, y no he analizado a fondo toda la discusión pasada, pero esto me suena realmente mal. ¿Qué pasa si la macro quiere generar elementos auxiliares a los que solo puede acceder la macro?

En lugar de descartar la higiene, creo que es mejor imponer una higiene total al 100%, pero proporcionar una forma para que las macros rechacen explícitamente la higiene para una variable en particular.

@joshtriplett , usaría Display impl para Literal.

@joshtriplett sí, como @dtolnay mencionó que Display que es en lo que se basa una caja como

Esta ronda de estabilización está destinada a ser "máximamente mínima" en el sentido de que proporciona la menor cantidad de funcionalidad para cubrir todos los casos de uso (también conocido como Display por Literal y nada más para interpretarlo ).

@Pauan no es genial, sí, pero es exactamente lo mismo que macro_rules! que se ha mantenido estable durante años y funciona en muchos contextos diferentes. Queremos permitir la higiene y un mejor tratamiento aquí, pero aún no estamos listos. El constructor Span::call_site() es el eje aquí donde al usar eso estás solicitando "no higiene". Eventualmente estabilizaremos más opciones.

Desafortunadamente, faltan años para lograr una "higiene total al 100%", y el propósito de esta propuesta es lograr algo estable para Rust 2018.

@alexcrichton Entonces, ¿el plan es estabilizarlo ahora con un agujero de higiene y luego un par de épocas / eras / ediciones arreglan ese agujero de higiene?

Dado que existe Span::call_site() , ¿hay alguna razón por la que no pueda tener una higiene completa en este momento? ¿Es una falta de mano de obra / tiempo, o hay preocupaciones teóricas / semánticas que aún deben desarrollarse en un RFC?

@Pauan para reiterar que no hay un "agujero" real en el sentido de que ya existe hoy. Esta es exactamente la misma historia de higiene con macro_rules! y derivación personalizada. Esta propuesta es efectivamente una extensión de eso, sin introducir nada nuevo.

Dada una "historia de higiene perfecta", siempre querremos alguna forma de exclusión voluntaria. Actualmente, esa exclusión voluntaria es Span::call_site() (efectivamente). Solo estabilizando eso, solo estamos estabilizando un mecanismo de exclusión voluntaria para la higiene. Con el tiempo, estabilizaremos más funciones para que los artículos sean completamente higiénicos cuando sea necesario.

La estabilización de la higiene está mucho más lejos. Hay (AFAIK) preguntas de investigación sin resolver, no es una cuestión de mano de obra.

@dtolnay Ah, ya veo. Entonces, ¿genera texto y luego vuelve a analizar el texto? Supongo que funciona por el momento.

cc @ rust-lang / compiler, todos ustedes que conozco también están muy interesados ​​en esto y no dude en plantear cualquier objeción. Si tiene una objeción de bloqueo, también puedo registrarla por usted

Todavía tengo algunas cosas que revisar y un PR con un par de ajustes de API de proc-macro en progreso.

¡Esta es exactamente la misma historia de higiene con macro_rules! y derivado personalizado.

Claro, pero pensé que uno de los objetivos era hacer un mejor sistema macro, por lo que señalar el sistema existente (roto y limitado) no me parece muy convincente.

Dada una "historia de higiene perfecta", siempre querremos alguna forma de exclusión voluntaria.

Absolutamente, pero mi punto es que dado que es posible usar Span::call_site() para romper la higiene (y así obtener la funcionalidad macro_rules! ) si lo desea, al hacerlo higiénico de forma predeterminada, obtiene acceso tanto a la higiene como no higiene. Mientras que si se estabiliza con la falta de higiene, entonces se atasca solo con la falta de higiene.

Con el tiempo, estabilizaremos más funciones para que los artículos sean completamente higiénicos cuando sea necesario.

Eso suena como una curita bastante molesta (y confusa): las macros proc serían higiénicas en la mayoría de las situaciones (pero no en los artículos), pero luego puede usar una nueva función para optar por la higiene de los artículos. ¿Lo estoy entendiendo bien?

Hay (AFAIK) preguntas de investigación sin resolver, no es una cuestión de mano de obra.

Está bien, eso es bastante justo. Entiendo el deseo de conveniencia y pragmaticismo. Siempre y cuando el plan es tener finalmente la higiene sólida por defecto en una época posterior / era / edición, entonces yo estoy bien con tener temporalmente la mala higiene. Simplemente no quiero que estabilicemos algo de lo que nos arrepentiremos más tarde.

En cierto sentido, ya es "higiénico por defecto", es solo que el predeterminado todavía no es compatible. Span::call_site es la opción de exclusión. :)

@Pauan Para @alexcrichton :

La construcción de un identificador requiere un Span , que contiene información sobre higiene. (Ver Term::new )

En el futuro, podemos exponer muchas formas diferentes de construir Span s, que reflejan diferentes opciones de higiene. Pero por ahora, solo expondremos Span::call_site que toma el alcance de la persona que llama.

De esta manera, podemos evitar estabilizar todo el sistema de higiene de inmediato, mientras mantenemos abierta la posibilidad de agregar higiene más tarde. ¡Creo que es un truco bastante inteligente para solucionar el problema!

@rpjohnst ¿Quiere decir que la única forma de devolver nuevos elementos desde una macro proc es usar Span::call_site ?

Si es así, suena perfecto: en ese caso, la higiene se puede agregar en el futuro de una manera limpia y compatible con versiones anteriores.

@lfairy Ahhh, ya veo, no me había dado cuenta de que era necesario usar Span::call_site , pensé que había un alcance antihigiénico predeterminado implícito. ¡Gracias por la explicación! Tienes razón, es un truco muy inteligente.

Como tal, no tengo más objeciones.

@alexcrichton

Atributos, macro_reglas y procedimientos
todas las macros residen en el espacio de nombres maro.

La última vez que verifiqué con #[feature(proc_macro)] , tenía un cambio incompatible con versiones anteriores en el código estable para la caja de derivación-error-cadena como se describe aquí. De la declaración citada, parece que seguirá siendo así en macros 1.2. ¿Es eso correcto?

@Arnavion oh cielos, ¡eso suena mal! Realmente no podemos hacer grandes cambios incompatibles con versiones anteriores, por lo que tendremos que encontrar una manera de hacer que eso siga funcionando. Una posible solución sería posponer los errores de "esto no es un atributo" hasta después de la expansión #[derive] .

Parece que # 48644 y # 47786 están listos. ¿Alguien podría actualizar el OP?

@alexcrichton ¿Ha habido alguna discusión sobre permitir el acceso a los datos internos de Literal y amigos? Entiendo que ya no son enumeraciones por razones de compatibilidad con versiones anteriores, pero ¿hay alguna razón por la que no podamos tener algo como esto por Literal para empezar?

    impl Literal {
        pub fn as_str(&self) -> Option<&str> {}
        pub fn to_int(&self) -> Option<i64> {}
        pub fn to_uint(&self) -> Option<u64> {}
        pub fn to_float(&self) -> Option<f64> {}
    }

Incluso podríamos tener un montón de TryFrom impls para los diferentes subtipos literales.

@abonander se ha discutido, sí, pero la conclusión ha sido agregarlos más tarde en lugar de hacerlos necesarios para el primer paso de estabilización. Se pueden construir en crates.io con la implementación Display y tenemos espacio para agregar más tarde en el futuro

: bell: Esto ahora está entrando en su período de comentarios final , según la revisión anterior . :campana:

@alexcrichton
!Send implicaciones de !Sync para los tipos de API de macro proc no se escriben explícitamente, sino que se infieren.
Para algunas estructuras (por ejemplo, Op ), el impl inferido difiere de lo que se especifica en https://github.com/rust-lang/rust/issues/38356#issuecomment -383693017.
Probablemente tenga sentido agregar las implicaciones explícitamente.

¡Vaya, sí! Abrí https://github.com/rust-lang/rust/pull/50453 para abordar eso

@alexcrichton Tenemos un problema desagradable con Term::as_str : estaba tratando de esbozar una prueba informal de que, debido a un alcance estricto, &'a Term -> &'a str se puede implementar para pedir prestado a algún interno con alcance, y 'a nunca podría ser más grande que el alcance del interno en sí (lo que solo importa si la función tiene éxito, es decir, si se llama dentro de ese alcance durante el cual el interno está activo).

AFAICT, Term::as_str es correcto, pero solo asumiendo que 'a condición.

Lo cual está respaldado por, por ejemplo, thread_local! , porque, si bien le permite escapar del Term , le da 'a s de muy corta duración, que si Term::as_str tiene éxito, son estrictamente más cortos que el alcance interno.
En general, la forma en que ocurre la expansión proc_macro , y debido a que Term es local en el hilo, hay muy pocas formas de escapar Term , y asumí que thread_local! fue efectivamente el único.

¡Pero Box::leak también existe! Todavía es inestable, pero hoy, Box::leak(Box::new(term)).as_str() devuelve &'static str . Me pregunto si hay otras abstracciones rotas por Box::leak (cc @RalfJung)

OTOH, esto solo es complicado porque Term no puede poseer los datos de la cadena, ya que es Copy .
Si eliminamos el Copy en Term , podríamos mantener un Option<Cell<Rc<String>> perezoso allí.

@eddyb oh Term::as_str está programado para su eliminación y no se incluyó en la estabilización aquí, ¡así que no hay nada de qué preocuparse! Simplemente se queda para no romper proc-macro2 , pero una vez que esto se estabilice, podemos lanzar un cambio de ruptura por proc-macro2

@eddyb No conozco el contexto aquí, pero Box::leak está justificado en mi modelo formal. Si posee algo de memoria para siempre (es decir, en una caja), puede decir totalmente que tiene alguna vida.

Tengo algunas preguntas:

  1. ¿No se está estabilizando quote! ?
  2. Habrá quote! tienen el proc_macro_non_items función de puerta que se le aplica? Confirmar 79630d4fdfc775b241cae0a209edec2687a29f0f ahora lo requiere, pero quote! todavía está marcado como #[unstable(feature = "proc_macro" ... .
  3. ¿Se presentarán problemas de seguimiento para la estabilización de proc_macro_path_invoc , proc_macro_mod , proc_macro_expr y proc_macro_non_items ?

Pregunta secundaria no relacionada: ¿dónde se implementa quote! ?

@mjbshaw Historia muy divertida: está implementada en proc_macro::quote .
rustc_metadata pretende que cualquier caja llamada proc_macro contiene una macro de procedimiento llamada quote , pero la implementación utilizada es de proc_macro rustc_metadata enlaces en contra.

Todavía tengo algunas cosas que revisar y un PR con un par de ajustes de API de proc-macro en progreso.

Revisión de relaciones públicas: https://github.com/rust-lang/rust/pull/50473

Solicitud de función para la API 1.2: agregue un delimitador para los corchetes angulares ( < / > ) para que cosas como <T> (en fn foo<T>() {} ) se analicen como a Group . No hacer esto hace que el análisis, por ejemplo, los genéricos, sea innecesariamente complicado.

@mjbshaw No creo que funcione a nivel de token intentar determinar si dos < > están agrupados entre sí. Por ejemplo, en la siguiente entrada de macro:

m!($A<$B, $C>=$D);

Tal vez se trate de dos expresiones booleanas $A < $B y $C >= $D , o tal vez represente genéricos en un alias de tipo, por ejemplo expandiéndose a type $A <$B,$C> = $D; .

assert_both!(a<AMAX, b>=BMIN);

define_type_alias!(SwappedResult<E, T>=std::result::Result<T, E>);

Actualicé ligeramente el OP, pero tenemos lo que me parecen dos posibles errores relacionados con la higiene, dependiendo de cómo resulten:

Para aquellos que siguen este hilo, es probable que la API cambie del comentario original de FCP en https://github.com/rust-lang/rust/pull/50473 propuesto por @petrochenkov. El resumen hasta ahora es:

  • Cambie el nombre de Term::new a Term::ident y valide la entrada
  • Agregue Term::lifetime y valide la entrada
  • Agregue Term::raw_ident y valide la entrada
  • Cambiar el nombre de Op a Punct
  • Validar entrada en Punct::new
  • Cambiar el nombre de Op::op a Punct::as_char

Una solicitud menor de API que haría (posiblemente en # 50473 - @petrochenkov) es alguna forma de agregar tokens a un TokenStream. Posiblemente:

impl Extend<TokenTree> for TokenStream

Creo que esto haría posible eliminar el tipo quote::Tokens (que es básicamente Vec<TokenTree> ) y reducir la proliferación de diferentes tipos en el ecosistema que significan "algunos tokens" - rastreados en https : //github.com/dtolnay/syn/issues/205.

+1 en la sugerencia anterior de @ dtolnay.

El período de comentarios final, con una disposición para fusionarse , según la revisión anterior , ahora está completo .

Tengo dos preguntas:

  1. Como ya se preguntó aquí , ¿qué pasa con quote! ? ¿Cuál debería ser la forma predeterminada de crear el TokenStream final? ¿Debe hacerse manualmente? ¿O debería uno usar la caja quote ? ¿Se supone que proc_macro::quote! se estabilizará en algún momento en el futuro?

  2. ¿Es mi entendimiento correcto en el sentido de que la diferencia entre declarar una macro de función y una macro de atributo es solo el número de argumentos? Es decir:

    /// Invoked as `foo!()`
    #[proc_macro]
    pub fn foo(a: TokenStream) -> TokenStream {
        // ...
    }
    
    /// Invoked as `#[bar]`
    #[proc_macro]
    pub fn bar(attr: TokenStream, item: TokenStream) -> TokenStream {
        // ...
    }
    

    La única diferencia es que uno toma un TokenStream como argumento, mientras que el otro toma dos . ¿No es esto un poco sutil? ¿Por qué no usar #[proc_macro_attribute] y #[proc_macro_function_like] lugar? ¿Se ha hablado de esto en alguna parte? Si es así, estaría feliz si alguien pudiera vincular la discusión.

¡Gracias por tu trabajo en esto! :)

@LukasKalbertodt Los atributos se declaran actualmente con #[proc_macro_attribute] . No sé si hay una intención deliberada de cambiar eso o si es un error tipográfico en la propuesta de FCP.

Problema: los tokens analizados a partir de cadenas no obtienen Span::call_site intervalos: https://github.com/rust-lang/rust/issues/50050#issuecomment -390520317.

Creo que tenemos que cambiar esto y también cambiar lo que Span::call_site devuelve para corregir los retrocesos de macros, el recorte y la higiene de edición de los tokens que utilizan tramos de sitios de llamadas.

@LukasKalbertodt la quote! en la caja proc_macro no se está estabilizando como parte de este FCP, pero la caja quote en crates.io se basa en la API propuesta aquí. Además, como @abonander señaló, las macros de atributos se declaran con #[proc_macro_attribute] y #[proc_macro] se reservan exclusivamente para las macros de estilo foo!()

¿No debería #[proc_macro_attribute] llamarse #[proc_attribute_macro] o #[attribute_proc_macro] ?

@Zoxc Ya tenemos #[proc_macro_derive] estable, por lo que sería extraño no seguir eso para las macros de atributos.

¿Podemos obtener PartialEq<char> y PartialEq<Punct> por Punct (similar a las implementaciones de Ident PartialEq )? Parece que debería ser bastante seguro agregarlo. Estoy feliz de escribir las relaciones públicas, pero no quiero hacerlo si la idea es un fracaso.

@mjbshaw ¿ PartialEq<Punct> también compararía tramos? PartialEq<char> parece estar bien, OTOH.

@eddyb PartialEq por Ident no compara intervalos (sé que esta es la fuente proc-macro2 y no la fuente proc-macro). Soy ambivalente en cuanto a si los intervalos se incluyen en la comparación, pero esperaría que Punct y Ident comporten de manera similar a este respecto. Punct también tiene su propio Spacing , que supongo que se incluiría en la comparación (aunque tal vez otros piensen de manera diferente).

Estaría bien solo implementando PartialEq<char> por Punct por ahora. PartialEq<Punct> se puede eliminar más tarde.

@mjbshaw la caja proc-macro2 tiene la libertad de no ser exactamente lo que proc_macro es aguas arriba y nos da cierta libertad para experimentar con varios ajustes. Sospecho que si funciona bien en crates.io, podemos agregarlo a proc_macro , pero, por supuesto, es compatible con versiones anteriores para agregarlo a proc_macro por lo que comenzamos con el mínimo y podemos escalar desde allí una vez que sea estable.

He realizado un trabajo de clasificación para todos los errores relacionados con las macros 1.2 . La mayoría de los errores se pueden clasificar en "errores graves" o "errores relacionados con todo el intervalo". Actualmente, los errores relacionados con el intervalo afectan únicamente a los mensajes de error (ya que la intención de las macros 1.2 no es cambiar la resolución). El error restante no relacionado con el intervalo (también conocido como grave) es https://github.com/rust-lang/rust/issues/50050 , para el cual @petrochenkov tiene una solución .

Gnome-class rompió con los cambios a proc_macro2 / syn / quote, más la puerta de función para generar módulos a partir de macros proc. Afortunadamente, ahora está arreglado.

¿Qué cosas debo monitorear para estar al tanto de los cambios en este pequeño ecosistema?

@federicomenaquintero Si usa funciones inestables, considere tener un trabajo de CI regular (diario, semanal, lo que sea que funcione para usted) que compile su código con el último Nightly y le notifique si falla. (Travis-CI admite la habilitación de dicho "trabajo cron" en su configuración).

@SimonSapin gracias, es una buena idea. Fijamos versiones de esas cajas en nuestro Cargo.toml, pero puede que sea el momento de eliminar los números de versión y dejar que Cargo descargue la última. ¿Es esta la forma correcta de hacerlo?

@federicomenaquintero Esto está cada vez más fuera de tema, por lo que si desea continuar con esta discusión, hágalo en otro lugar, como IRC o http://users.rust-lang.org/ , pero la recomendación general es que las aplicaciones (como opuesto a las bibliotecas) debería enviar Cargo.lock junto con su código fuente, que efectivamente fija las dependencias. En Cargo.toml , se recomienda declarar una dependencia como foo = "1.2.3" , que implícitamente significa "esa versión o posterior, si es compatible según SemVer".

Entonces, acabo de encontrarme con un problema con macros de procedimiento que me está bloqueando al desarrollar una caja que quiero hacer.

Considera lo siguiente:

#[my_attribute]
struct MyStruct {
  #[other_attribute]
  field: String,
}

Actualmente, esto no funciona porque las funciones proc_macro y custom_attributes son necesarias pero no se pueden utilizar al mismo tiempo. Según tengo entendido, la estabilización de las macros proc eliminaría la necesidad de los indicadores de funciones.

La otra cosa es que de esta manera #[my_attribute] podría generar un código que evite que se ejecute #[other_attribute] . ¿Qué sería realmente genial si en el atributo "externo", pudiera registrar atributos internos que funcionan de la misma manera que funcionan #[derive(Foo)] ?

¿Qué pasa con el comentario de @SimonSapin sobre la sesión ficticia ?

¿Sería posible / deseable reemplazar este pánico con la creación implícita de una "sesión" ficticia? ¿O quizás agregar una API pública (con una ruta de estabilización) para crear una?

Creo que sería muy útil tener una sesión ficticia. Escribir una prueba unitaria para cajas de proc-macro es prácticamente imposible o al menos muy inconveniente de lo contrario. Además, no solo es TokenStream::from_str , sino también otras funciones que requieren una sesión.

@alexcrichton

He realizado un trabajo de clasificación para todos los errores relacionados con las macros 1.2. La mayoría de los errores se pueden clasificar en "errores graves" o "errores relacionados con todo el intervalo".

Me gustaría actualizar https://github.com/rust-lang/rust/issues/50504 al estado "grave": el problema del módulo descrito es solo un síntoma de un problema más profundo: las ID de expansión para macros proc no estar registrado correctamente. No sé qué otras consecuencias puede tener esto.
Hay un PR que soluciona el problema subyacente (https://github.com/rust-lang/rust/pull/51952), pero hay regresiones de la solución y aún no las he revisado.

Publiqué un PR para estabilizar más macros de procedimiento en https://github.com/rust-lang/rust/pull/52081

@petrochenkov me suena bien, comentaré sobre las relaciones públicas

Acabo de publicar sobre el problema del seguimiento de nombres de macros sobre problemas con los atributos secundarios proc_macro_derive y cómo interactúan con el sistema de nombres. Hay otro problema con la forma en que los atributos secundarios proc_macro_derive interactúan con el alcance y la denominación, pero parece más relevante mencionarlo aquí. Dado que las rutas de los atributos no están actualmente en curso de estabilización, tenemos la posibilidad de que #[derive(foo::Parent)] pueda tener un atributo secundario #[foo::Child] , pero la macro de derivación no tendría forma, a primera vista, de identificar si el atributo hijo es en realidad su propio hijo, ya que no puede realizar la búsqueda de nombres. Por ahora, no tengo una solución fácil, pero creo que es algo que debería estar en el radar para el futuro de los atributos interdependientes; No hay ninguna razón por la que los atributos proc_macro_attribute no quieran interactuar de una manera que se encuentre con problemas de búsqueda similares.

Intenté compilar mi proyecto hoy, pero algo está roto y probablemente esté relacionado con este problema. Todos los mensajes de error tenían el mensaje: "(consulte el número 38356)". Así es como llegué aquí.
Incluyo aquí el mensaje de error que recibí durante la compilación. También incluyo mi Cargo.toml.

Encuentro esto muy sorprendente, ya que mi proyecto está anclado a una versión nocturna específica de Rust (rustc 1.29.0-nightly (9bd8458c9 2018-07-09)) ¿Qué podría haber cambiado? ¿Posiblemente una biblioteca actualizada?

Cargo.toml

[[bin]]
name = "main"
path = "src/bin/main.rs"

[dependencies]
log = "0.4"
pretty_env_logger = "0.2"

rand = "0.4"
ring = "=0.13.0-alpha"
untrusted = "0.6"

bytes = "0.4"
futures = "0.1"
tokio-io = "0.1"
tokio-core = "0.1"
futures-await = "0.1"

capnp = "0.8"
rusqlite = "0.13"

async_mutex = { git = "https://github.com/realcr/async_mutex", rev = "a1d973ed7" }

num-bigint = "0.2.0"
num-traits = "0.2.4"

[dev-dependencies]

[dependencies.byteorder]
version = "1.1"
features = ["i128"]

[build-dependencies]
capnpc = "0.8"

[profile.release]
debug = true

Errores de compilación

$ cargo test
    Updating git repository `https://github.com/realcr/async_mutex`
   Compiling proc-macro2 v0.4.8                                                                                                                                                                                    
   Compiling cswitch v0.1.0 (file:///home/real/projects/d/cswitch)                                                                                                                                                 
error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)8: proc-macro2                                                                                                                        
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:33:40
   |
33 |     let works = panic::catch_unwind(|| proc_macro::Span::call_site()).is_ok();
   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:213:13
    |
213 |     Nightly(proc_macro::token_stream::IntoIter),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:438:11
    |
438 | impl From<proc_macro::Span> for ::Span {
    |           ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:284:13
    |
284 |     Nightly(proc_macro::SourceFile, FileName),
    |             ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:332:13
    |
332 |     Nightly(proc_macro::Span),
    |             ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:461:13
    |
461 |     Nightly(proc_macro::Ident),
    |             ^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:523:13
    |
523 |     Nightly(proc_macro::Literal),
    |             ^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:116:47
    |
116 |                     Delimiter::Parenthesis => proc_macro::Delimiter::Parenthesis,
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:117:43
    |
117 |                     Delimiter::Bracket => proc_macro::Delimiter::Bracket,
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:118:41
    |
118 |                     Delimiter::Brace => proc_macro::Delimiter::Brace,
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:119:40
    |
119 |                     Delimiter::None => proc_macro::Delimiter::None,
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:122:33
    |
122 |                 let mut group = proc_macro::Group::new(delim, tt.stream.inner.unwrap_nightly());
    |                                 ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:128:39
    |
128 |                     Spacing::Joint => proc_macro::Spacing::Joint,
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:129:39
    |
129 |                     Spacing::Alone => proc_macro::Spacing::Alone,
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:131:30
    |
131 |                 let mut op = proc_macro::Punct::new(tt.as_char(), spacing);
    |                              ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:113:17
    |
113 |         let tt: proc_macro::TokenTree = match token {
    |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:238:13
    |
238 |             proc_macro::TokenTree::Group(tt) => {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:240:21
    |
240 |                     proc_macro::Delimiter::Parenthesis => Delimiter::Parenthesis,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:241:21
    |
241 |                     proc_macro::Delimiter::Bracket => Delimiter::Bracket,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:242:21
    |
242 |                     proc_macro::Delimiter::Brace => Delimiter::Brace,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:243:21
    |
243 |                     proc_macro::Delimiter::None => Delimiter::None,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:250:13
    |
250 |             proc_macro::TokenTree::Punct(tt) => {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:252:21
    |
252 |                     proc_macro::Spacing::Joint => Spacing::Joint,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:253:21
    |
253 |                     proc_macro::Spacing::Alone => Spacing::Alone,
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:259:13
    |
259 |             proc_macro::TokenTree::Ident(s) => ::Ident::_new(Ident::Nightly(s)).into(),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:260:13
    |
260 |             proc_macro::TokenTree::Literal(l) => ::Literal::_new(Literal::Nightly(l)).into(),
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:289:20
    |
289 |     fn nightly(sf: proc_macro::SourceFile) -> Self {
    |                    ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:339:27
    |
339 |             Span::Nightly(proc_macro::Span::call_site())
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:347:27
    |
347 |             Span::Nightly(proc_macro::Span::def_site())
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:369:30
    |
369 |     pub fn unstable(self) -> proc_macro::Span {
    |                              ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:430:32
    |
430 |     fn unwrap_nightly(self) -> proc_macro::Span {
    |                                ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:439:24
    |
439 |     fn from(proc_span: proc_macro::Span) -> ::Span {
    |                        ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:468:48
    |
468 |             Span::Nightly(s) => Ident::Nightly(proc_macro::Ident::new(string, s)),
    |                                                ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:475:48
    |
475 |             Span::Nightly(s) => Ident::Nightly(proc_macro::Ident::new_raw(string, s)),
    |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:495:32
    |
495 |     fn unwrap_nightly(self) -> proc_macro::Ident {
    |                                ^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:583:30
    |
583 |             Literal::Nightly(proc_macro::Literal::f32_unsuffixed(f))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:591:30
    |
591 |             Literal::Nightly(proc_macro::Literal::f64_unsuffixed(f))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:599:30
    |
599 |             Literal::Nightly(proc_macro::Literal::string(t))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:607:30
    |
607 |             Literal::Nightly(proc_macro::Literal::character(t))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:615:30
    |
615 |             Literal::Nightly(proc_macro::Literal::byte_string(bytes))
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:636:32
    |
636 |     fn unwrap_nightly(self) -> proc_macro::Literal {
    |                                ^^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/lib.rs:322:30
    |
322 |     pub fn unstable(self) -> proc_macro::Span {
    |                              ^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:531:34
    |
531 |                   Literal::Nightly(proc_macro::Literal::$name(n))
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
...
552 | /     suffixed_numbers! {
553 | |         u8_suffixed => u8,
554 | |         u16_suffixed => u16,
555 | |         u32_suffixed => u32,
...   |
565 | |         f64_suffixed => f64,
566 | |     }
    | |_____- in this macro invocation
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:543:34
    |
543 |                   Literal::Nightly(proc_macro::Literal::$name(n))
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
...
568 | /     unsuffixed_integers! {
569 | |         u8_unsuffixed => u8,
570 | |         u16_unsuffixed => u16,
571 | |         u32_unsuffixed => u32,
...   |
578 | |         isize_unsuffixed => isize,
579 | |     }
    | |_____- in this macro invocation
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:45:34
   |
45 |             TokenStream::Nightly(proc_macro::TokenStream::new())
   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
  --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:53:46
   |
53 |             TokenStream::Nightly(tts) => tts.is_empty(),
   |                                              ^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:123:23
    |
123 |                 group.set_span(span.inner.unwrap_nightly());
    |                       ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:132:20
    |
132 |                 op.set_span(tt.span().inner.unwrap_nightly());
    |                    ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:239:38
    |
239 |                 let delim = match tt.delimiter() {
    |                                      ^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:245:74
    |
245 |                 let stream = ::TokenStream::_new(TokenStream::Nightly(tt.stream()));
    |                                                                          ^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:247:58
    |
247 |                 g.set_span(::Span::_new(Span::Nightly(tt.span())));
    |                                                          ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:251:40
    |
251 |                 let spacing = match tt.spacing() {
    |                                        ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:255:43
    |
255 |                 let mut o = Punct::new(tt.as_char(), spacing);
    |                                           ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:256:58
    |
256 |                 o.set_span(::Span::_new(Span::Nightly(tt.span())));
    |                                                          ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:290:45
    |
290 |         let filename = stable::file_name(sf.path().to_string());
    |                                             ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:304:44
    |
304 |             SourceFile::Nightly(a, _) => a.is_real(),
    |                                            ^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:355:69
    |
355 |             (Span::Nightly(a), Span::Nightly(b)) => Span::Nightly(a.resolved_at(b)),
    |                                                                     ^^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:363:69
    |
363 |             (Span::Nightly(a), Span::Nightly(b)) => Span::Nightly(a.located_at(b)),
    |                                                                     ^^^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:424:55
    |
424 |             (Span::Nightly(a), Span::Nightly(b)) => a.eq(b),
    |                                                       ^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:482:50
    |
482 |             Ident::Nightly(t) => Span::Nightly(t.span()),
    |                                                  ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:489:56
    |
489 |             (Ident::Nightly(t), Span::Nightly(s)) => t.set_span(s),
    |                                                        ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:623:56
    |
623 |             Literal::Nightly(lit) => Span::Nightly(lit.span()),
    |                                                        ^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error[E0658]: use of unstable library feature 'proc_macro' (see issue #38356)
   --> /home/real/.cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-0.4.8/src/unstable.rs:630:62
    |
630 |             (Literal::Nightly(lit), Span::Nightly(s)) => lit.set_span(s),
    |                                                              ^^^^^^^^
    |
    = help: add #![feature(proc_macro)] to the crate attributes to enable

error: aborting due to 63 previous errors

For more information about this error, try `rustc --explain E0658`.
error: Could not compile `proc-macro2`. 

¿Tiene una idea de lo que pudo haber salido mal y cómo se puede solucionar? ¡Gracias!

@realcr para la proc-macro2 , simplemente puede ejecutar cargo update y eso debería funcionar!

@alexcrichton No creo que ese sea el problema aquí. Prefiero pensar que @realcr ya actualizó proc-macro2 ya que el mensaje de error dice proc-macro2-0.4.8 todas partes. El problema es más bien que la versión nocturna está arreglada en una que no incluye # 52081. Hoy tuve el mismo problema y me preguntaba por qué proc-macro2 solo superó la versión menor. Pero no estoy muy familiarizado con cómo proc-macro2 maneja la compatibilidad.

@realcr Intente actualizar su compilador nocturno o aplique una proc-macro-2 versión < 0.4.8 en su proyecto.

@alexcrichton , @LukasKalbertodt : Gracias por la rápida respuesta.
Acabo de actualizar mi compilador nocturno a la última versión. Eliminó los problemas de proc-macro-2, pero obtuve muchos errores de compilación nuevos. Ejemplo:

error[E0277]: the trait bound `impl futures::Future: std::future::Future` is not satisfied
   --> src/networker/messenger/handler/handle_neighbor.rs:191:25
    |
191 |         let signature = await!(self.security_module_client.request_signature(failure_signature_buffer))
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `impl futures::Future`
    |
    = note: required by `std::future::poll_in_task_cx`
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

...

error[E0627]: yield statement outside of generator literal
   --> src/networker/messenger/handler/handle_neighbor.rs:403:13
    |
403 | /             await!(self.reply_with_failure(remote_public_key.clone(), 
404 | |                                            channel_index,
405 | |                                            request_send_msg.clone()))?
    | |_____________________________________________________________________^
    |
    = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Para confirmar, mi versión actual de rustc:

rustc 1.29.0-nightly (1ecf6929d 2018-07-16)

Para rastrear la fuente del problema, intenté compilar el ejemplo básico de futures_await pero también dejó de funcionar. Presentaré un problema allí para que podamos resolver este problema.

@LukasKalbertodt https://github.com/alexcrichton/proc-macro2#unstable -features

Porque estás usando la función inestable.

@realcr, su nuevo problema de compilación no está relacionado con este problema, permanezca en el tema.

@TeXitoi : Siéntase libre de editar o eliminar cualquier cosa si cree que no es relevante. Hago todo lo posible para ayudarlo, es difícil para mí saber qué está en el tema y qué no. El mensaje de error "(consulte el número 38356)" es lo que me trajo aquí.

Intenté actualizar la versión de mi compilador y aparece este error. Mi código

#![no_std]
#![feature(proc_macro)]
#![feature(proc_macro_gen)]
#![feature(custom_attribute)]
#![feature(alloc)]

#[macro_use(eth_abi)]
extern crate pwasm_abi_derive;

y error que dice que no usé #![feature(proc_macro)] , ¡pero lo hice!

error[E0658]: attribute procedural macros are experimental (see issue #38356)
  --> src\lib.rs:67:5
   |
8  | #[macro_use(eth_abi)]
   |             ------- procedural macro imported here
...
67 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: add #![feature(proc_macro)] to the crate attributes to enable

@Pzixel querrás cambiar #![feature(proc_macro)] a #![feature(use_extern_macros)] y eso debería funcionar

Creo que también necesitará usar el sistema de módulos para importar macros de procedimiento (y asegúrese de tener un compilador nocturno actualizado)

@alexcrichton sí, lo acabo de descubrir, gracias al artículo . Sin embargo, todavía no funciona:

error[E0433]: failed to resolve. Use of undeclared type or module `Vec`
  --> src\lib.rs:66:5
   |
66 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `Vec`

error[E0412]: cannot find type `Vec` in this scope
  --> src\lib.rs:66:5
   |
66 |     #[eth_abi(TokenEndpoint, TokenClient)]
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope

¿Las reglas de importación para macros también han cambiado? O no puedo entender por qué empezó a quejarse aquí.

@Pzixel que puede ser un error en la macro de procedimiento o el compilador, ¿puede presentar un problema

Bueno, creo que primero debería reescribir mi código para que al menos parezca que funciona :) Ahora mismo no es así, ustedes cambiaron mucho con esta característica. BRB cuando termine. Si no desaparece, creo un problema.

@alexcrichton
¿Sabe qué "preprocesamiento" se aplica a los tokens antes de que se pasen a una macro de procedimiento?
Sé que los derivados tienen al menos $crate eliminados y cfg expandidos antes de que obtengan los tokens de entrada (además de los viajes de ida y vuelta a través de cadenas no están del todo sin pérdidas, pero eso se puede arreglar).

Debemos asegurarnos de que nada de esto suceda con macros de procedimiento recién estabilizadas y que obtengan tokens de entrada con precisión (errores de módulo).

@alexcrichton lo siento, cargo expand no funciona en esta caja por alguna razón. No puedo confirmar si el problema está en mi lado o en el compilador uno. Así que seguiré culpándome a mí mismo hasta que esta posibilidad no quede completamente excluida.

@petrochenkov, la expansión de proc-macros ha sido bastante bien examinada hasta la fecha, así que estoy mucho menos preocupado por eso que por las piezas de resolución de nombres. Personalmente, no estoy al tanto del preprocesamiento, pero sé que hay un orden de expansión en el que las derivadas se ejecutan en último lugar, los cfgs se ejecutan primero y, por lo demás, es principalmente iterativo.

Sin embargo, estoy de acuerdo en que es bueno auditar.

Quizás me perdí algo obvio. Pero, ¿no hay forma de llamar a una función, usar un tipo, etc. desde la caja que define proc_macro desde una macro expansión de procedimiento? (o cualquier otra caja conocida de la caja proc_macro, FWIW)

Hay soluciones , pero AFAIU no funcionarán si el usuario de la macro de procedimiento cambia el nombre de la caja.

Las cajas proc-macro de construir cajas que las utilicen. No son dependencias de tiempo de ejecución. Puede pensar en toda la caja proc-macro como una especie de complemento del compilador, no como una biblioteca "normal".

Esto es especialmente visible cuando se realiza una compilación cruzada: al igual que los scripts de compilación, las macros proc se compilan para la plataforma de host, no para la de destino.

@SimonSapin Estoy de acuerdo con usted, pero puede ser realmente útil delegar parte del trabajo a una función proporcionada por una caja, incluso si no es la caja proc-macro (por ejemplo, en mi enlace de arriba, el X-derive crate intenta usar una función de X crate). Porque de lo contrario, eso significaría que todo el código generado por proc-macros tiene que ser autocontenido o hacer suposiciones sobre el estado del sitio de la llamada.

Entonces, puedo entender que rustc aún no está listo para este tipo de función (porque supongo que funcionaría mejor sin la necesidad de dividir proc-macro de las cajas no proc-macro, que parece estar en algún lugar a largo plazo) hoja de ruta del término). Pero me pregunto, si la interfaz actual que usa solo TokenStreams está estabilizada, ¿será posible actualizar esta función más adelante? ¿No necesitaría algo como un tipo de token PathToBeResolvedFromTopOfGeneratingProcMacroCrate ? (que sería un cambio importante si se agrega más adelante, afaiu)

Quizás sea posible hacer las cosas más flexibles eventualmente, pero eso parece bastante lejano.

Mientras tanto, si es autor de una biblioteca, considere tener una caja foo-proc-macros o foo-derive para macros de procedimiento, y una biblioteca foo "normal" que contenga tiempo de ejecución código pero también reexporta las macros de procedimiento. De esa manera, la API de cara al usuario se puede mantener en una sola caja. Esto es lo que hace serde (en algunas configuraciones) https://github.com/serde-rs/serde/blob/v1.0.71/serde/src/lib.rs#L304

Sin embargo, vale la pena señalar que esta solución alternativa aún no resuelve el problema del cambio de nombre de la caja raíz por parte del usuario (por ejemplo, el

@Ekleog , TokenStream es un flujo de TokenTree sy cada TokenTree tiene asociado Span , que lleva la información de alcance. Excepto que actualmente no hay forma de crear un intervalo para ningún otro ámbito que no sea "llamar al sitio" (o vacío). Básicamente, lo que se necesita es idear una forma razonablemente ergonómica de crear Span s refiriéndose a una caja específica.

La razón por la que pregunté es que la casilla de verificación no está marcada. ¡Sería bueno marcarlo entonces!

Con #![feature(proc_macro)] estabilizado, ¿qué queda de este problema?

@ jan-hudec Oh, pensé que Span s eran solo para informes de errores, ya que las primeras publicaciones del blog mencionaban una estructura Hygiene (o con un nombre similar) que desempeñaba este papel. Había asumido que estos habían desaparecido y aparentemente estaba equivocado. ¡Gracias! :)

Con #! [Feature (proc_macro)] estabilizado, ¿qué queda de este problema?

Idealmente, se deben archivar los problemas nuevos para todos los problemas individuales restantes y las funciones no estabilizadas, y luego este problema se puede cerrar (de la misma manera que se hizo para https://github.com/rust-lang/rust/issues/ 44660).

Oh, pensé que los intervalos eran solo para informar errores, ya que las primeras publicaciones del blog mencionaron una estructura de higiene (o un nombre similar) que desempeñaba este papel. Había asumido que estos habían desaparecido y aparentemente estaba equivocado. ¡Gracias! :)

IIUC, los intervalos son la forma principal de rastrear el contexto de la higiene.

@ mark-im Algo así. Incluyen información de ubicación del código fuente (para mensajes / diagnósticos de cara al usuario) y contexto de sintaxis (es decir, información de higiene).

Dada la cantidad de discusión / tráfico que genera este problema, ¿tiene sentido mover proc_macro_diagnostic a su propio problema de seguimiento? También me gustaría averiguar cuáles son los bloqueadores para la estabilización de esa función y ver si podemos impulsarla. Diesel lo usa, y hasta ahora ha sido excelente. La falta de esta función en estable está llevando a la comunidad a crear soluciones alternativas, como la versión más reciente de syn que usa compile_error! en su lugar.

@sgrif He abierto un problema de este tipo: https://github.com/rust-lang/rust/issues/54140.

Así que estoy interesado en ayudar a estabilizar los métodos en Span y la estructura LineColumn. Veré los problemas abiertos en el primer comentario, pero si alguien quiere señalar a un novato al compilador en una dirección particular, lo agradecería: +1:

La puerta de función proc_macro_gen me señaló aquí, pero en la lista de verificación en la parte superior no veo nada que obviamente se refiera a una macro (proc_) que genera otras definiciones de macro. ¿Se ha tenido esto en cuenta (aparte de la puerta de características de rustc)?

@jjpe es probablemente mejor en este momento que

@alexcrichton Estoy perfectamente de acuerdo con eso, es más que en el proceso de mirar la función proc_macro_gen , me refirió aquí solo para encontrar tan bueno como no mencionarlo. Eso es un poco extraño para mí, así que decidí mencionarlo, al menos.

@xieyuheng ¿Cómo se vería CodeString / Code , es decir, cuál sería su semántica?
Tenga en cuenta que TokenStream no es más que el código fuente literalmente, excepto como una serie de valores de token en lugar de un texto molesto.

La API extendida para TokenStream (con TokenTree ) es estable en 1.29. La importación de macros proc similares a funciones será estable en 1.30.

Parece que desde rustc 1.30.0-nightly (63d51e89a 2018-09-28) ya no es posible recorrer el código dentro del módulo en un archivo separado. Si procesa mod module; , obtiene TokenStream contiene mod module; , WYSIWYG.

Entiendo que esto es necesario para preservar la amplitud, la higiene y la coherencia con el código procesado. ¿Existe o habrá alguna forma de trabajar con el contenido de los módulos en archivos separados? Su falta puede resultar confusa para los usuarios finales cuando la refactorización trivial de la organización del módulo provoca un cambio en el comportamiento de las macros.

Ok, este problema es masivo y ha llegado al punto en que no creo que sea demasiado útil mantener abierto más y rastrear las API. Con ese fin, he abierto https://github.com/rust-lang/rust/pull/54728 que divide este problema en varios problemas de seguimiento más detallados:

En este punto, voy a cerrar esto, pero si me he olvidado de separar cualquier otro problema de seguimiento, ¡avíseme! Ciertamente puedo abrir más seguimientos

@alexcrichton ¿Qué pasa con los sub-atributos para macro de tipo atributo?
https://github.com/rust-lang/rust/issues/38356#issuecomment -397095541
¿Hay algún problema para esto?

@XX
¿Estos atributos secundarios no tienen por qué ser necesariamente una característica del idioma?
En el caso de derive se necesita el registro de atributos personalizados porque las macros de derivación no pueden eliminar atributos de su entrada (la entrada es inmutable).
Las macros de atributo pueden eliminar #[other_attribute] s de su entrada, por lo que nunca llegarán a la resolución de nombres y nunca reportarán el error de "atributo no resuelto".

(Además de los atributos personalizados inestables heredados clásicos mencionados en https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541 ahora son compatibles con las macros proc).

@petrochenkov Sí, gracias por la aclaración.

¿Fue útil esta página
0 / 5 - 0 calificaciones