Rust: Problème de suivi pour la RFC 1566 : macros procédurales

Créé le 14 déc. 2016  ·  184Commentaires  ·  Source: rust-lang/rust

Statut actuel

Ce problème a été fermé en faveur de problèmes de suivi plus précis

~Description mise à jour ~

Prochaines étapes:

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

    • en attente sur le cratère

  • [ ] Stabiliser la fonction proc_macro

Les obstacles possibles à la stabilisation

Description d'origine

RFC .

Cette RFC propose une évolution du système de macros procédurales de Rust (aka syntaxe
extensions, alias plugins de compilateur). Cette RFC spécifie la syntaxe pour la définition
des macros procédurales, une vue de haut niveau de leur implémentation dans le compilateur,
et décrit comment ils interagissent avec le processus de compilation.

Au plus haut niveau, les macros sont définies en implémentant des fonctions marquées de
un attribut #[macro] . Les macros fonctionnent sur une liste de jetons fournis par le
compilateur et renvoie une liste de jetons par lesquels la macro est remplacée. Nous
fournir des installations de bas niveau pour opérer sur ces jetons. Niveau supérieur
les installations (par exemple, pour l'analyse des jetons vers un AST) devraient exister en tant que caisses de bibliothèque.

Feuille de route : https://github.com/rust-lang/rust/issues/38356#issuecomment -274377210.


Tâches

  • [x] Mettre en œuvre #[proc_macro_attribute] (PR #38842).

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

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

  • [x] Implémentez #[proc_macro] (PR #40129).
  • [x] Identifiez et collectez les utilisations de proc_macro_derive dans les InvocationCollector (PR #39391).
  • [x] Prise en charge des importations proc_macro_derive étendues par macro.

    • Par exemple:

#[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!();
  • [ ] Développez les éléments avant de développer les proc_macro_derive appliqués (PR #48465).
  • [x] Mettre en œuvre des avertissements pour les importations #[macro_use] inutilisées (PR #39060).
  • [x] Refactoriser l'analyseur pour consommer les arbres de jetons (PR #39118).
  • [x] Nettoyez TokenStream en vue d'une refactorisation ultérieure (PR #39173).
  • [x] Supprimer TokenTree::Sequence (PR #39419).
  • [x] Utiliser TokenStream s au lieu de Vec<TokenTree> en tokenstream::TokenTree s » Delimited variante (PR # 40202).
  • [x] Utilisez Path s et TokenStream s dans ast::Attribute s (PR #40346).

    • [x] Prise en charge des chemins non triviaux dans les macros d'attribut/dérivation (par exemple #[foo::bar] , #[derive(foo::Bar)] ).

  • [x] Incluez des informations d'hygiène avec tous les jetons, pas seulement les identifiants (PR #40597).
  • [x] Implémentez une API minimale pour proc_macro::TokenStream comme indiqué dans le RFC (PR #40939).

    • [x] Incluez les TokenStream sources pour les fragments AST interpolés dans les jetons Token::Interpolated .

    • [x] Incluez un TokenStream devis proc_macro::quote! derrière la porte de fonctionnalité proc_macro .

  • [x] Fournir un moyen pour les auteurs de proc_macro de créer des extensions qui utilisent des éléments dans une caisse prédéterminée foo sans exiger que l'utilisateur de la macro inclue extern crate foo; à la racine de la caisse (PR # 40939).

    • [ ] Améliorer l'ergonomie.

  • [ ] Inclure les sources TokenStream pour les éléments de l'AST.
  • [ ] Contrôle de stabilité (proc-)macros (issue #34079).
  • [x] Autoriser la macro proc à initialiser un champ privé avec une valeur def_site (problème #47311). (RP #48082)
  • [x] Incohérence entre l'accès au champ de la structure accolée et la structure tuple dans la macro proc (problème #47312). (RP #48083)
  • [ ] Rendre std disponible pour proc macro root dans la phase 1 (problème #47314).
  • [x] Amélioration de l'erreur de syntaxe invalide dans proc_macro::quote! (problème #47315).
  • [ ] Incohérence entre Display et IntoIterator pour un TokenStream contenant un module (issue #47627).
  • [x] #[cfg_attr] rend .to_string() et TokenStream en désaccord (problème #48644).
  • [x] Liste de souhaits pour libproc_macro (liste de contrôle dans #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

Commentaire le plus utile

Ok, ce problème est énorme et est arrivé au point que je ne pense pas qu'il soit trop utile de rester ouvert et de suivre les API. À cette fin, j'ai ouvert https://github.com/rust-lang/rust/pull/54728 qui divise ce problème en un certain nombre de problèmes de suivi plus précis :

À ce stade, je vais fermer ceci, mais si j'ai oublié de séparer d'autres problèmes de suivi, faites-le moi savoir ! Je peux certainement ouvrir d'autres suivis

Tous les 184 commentaires

cc @nrc @jseyfried

J'aimerais que #[proc_macro_attribute] soit bientôt implémenté. J'ai déjà un prototype et j'ai testé l'utilisation avant de me rendre compte qu'il n'y a pas encore de support de compilateur :unamused: :

Prototype : https://github.com/abonander/anterofit/blob/proc_macro/macros/src/lib.rs
Exemple/Test : https://github.com/abonander/anterofit/blob/proc_macro/examples/post_service_proc_macro.rs

Tâches

(modification dtolnay : a déplacé la liste de contrôle vers l'OP)

cc @nrc @petrochenkov @durka @Ralith

@jseyfried J'ai rencontré un problème où si une macro héritée et un attribut du même nom sont importés dans la même portée, essayer d'utiliser l'attribut génère une erreur indiquant que les macros ne peuvent pas être utilisées comme attributs. Pouvons-nous faire en sorte que les deux puissent être dans la même portée et puissent être utilisés comme prévu ?

@abonander Toutes les macros (bang, attribut et dérive) partagent le même espace de noms, nous ne pouvons donc pas utiliser deux macros différentes avec le même nom dans la même portée. Cependant, nous pourrions améliorer ce message d'erreur : pourriez-vous ouvrir un problème ?

Désolé, je suis en retard à la fête. Je suis satisfait de la direction pour exposer des jetons plutôt qu'un AST, mais j'ai quelques inquiétudes concernant l'API spécifique TokenStream proposée dans la 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,
}

Il n'est pas clair si cette API était conçue comme un plan complet qui a été accepté lors de la fusion de la RFC, ou simplement comme un exemple à élaborer plus tard.

Généralement, cela semble loin de la syntaxe Rust "normale" acceptée par le compilateur en dehors des macros. Alors que certaines macros voudront analyser un langage ad-hoc spécifique à un domaine, d'autres voudront analyser la syntaxe "Rust réelle" et lui donner un sens.

  1. (Mineur) Je ne pense pas que Eof soit nécessaire. Un Iterator sera probablement utilisé pour, eh bien, itérer sur un TokenStream et Iterator::next renvoie déjà None pour signaler la fin de l'itération.

  2. (Mineur) Je ne pense pas que Exclamation , Dollar , ou Semicolon soient nécessaires. Faire correspondre sur Punctuation('!') par exemple n'est pas plus difficile.

  3. (Mineur) Comme d'autres l'ont mentionné dans le RFC PR, nous pourrions vouloir omettre les commentaires qui ne sont pas des commentaires doc. (Tout cas d'utilisation qui souhaite conserver les commentaires souhaite également conserver les espaces.)

  4. Pour autant que je sache, que faire avec les opérateurs multi-caractères (qui devraient probablement être un seul jeton chacun) est toujours une question ouverte. Une solution possible est discutée dans les commentaires des relations publiques, mais il semble que cela n'ait pas été intégré au texte RFC.

  5. Les littéraux numériques sont manquants. Les macros sont-elles censées analyser [Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')] par elles-mêmes pour évaluer un littéral ? Ils ne peuvent même pas utiliser str::parse::<f32> pour faire cela, car la syntaxe qu'il accepte n'est pas la même que la syntaxe littérale Rust (qui peut avoir _ au milieu, par exemple).

    J'imagine qu'il y a un problème de stabilité ici. Pouvons-nous introduire de nouveaux types numériques comme u128 / i128 (et éventuellement à l'avenir f128 , u256 , …) et leurs littéraux, sans casser les modifications apportées à l'API des jetons ? Une façon de rendre cela possible pourrait être :

    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
    

    Ou peut-être autre chose. Mais je ne pense pas que "faire semblant que les chiffres n'existent pas" soit une bonne façon de le faire.

  6. // Le mot est défini par la norme Unicode Annexe 31 -

    Cette définition doit être plus précise que cela. UAX 31 spécifie quelques variantes différentes de la syntaxe des identifiants, et aucune d'entre elles n'est appelée "mot". Mais choisir la variation exacte que nous voulons est la raison pour laquelle les identifiants non ASCII sont actuellement limités par les fonctionnalités.

    Au lieu de cela, je pense que cela devrait être défini comme "tout ce que le compilateur actuel accepte comme identifiant ou mot-clé" (ce qui peut changer selon #28979). Peut-être avec une API publique pub fn is_identifier(&str) -> bool dans libmacro.

  7. Les chaînes Unicode et les littéraux de chaîne d'octets partagent une seule variante de jeton, ce qui, à mon avis, est faux car les représentations en mémoire de leurs valeurs ont des types différents ( str vs [u8] ). Il n'est pas non plus clair si le composant text: Symbol est destiné à être une tranche littérale du code source ou la valeur après la résolution des échappements antislash. Je pense que cela devrait certainement être le dernier. (À titre de comparaison, Char(char) doit être ce dernier puisque \u{A0} prend plus d'un char pour représenter littéralement.)

une autre façon d'écrire des macros de haut niveau serait d'utiliser des macros de type lisp, mais cela nécessiterait une représentation d'expression s pour l'ensemble de la rouille.

@SimonSapin ,

Comme d'autres l'ont mentionné dans le RFC PR, nous pourrions vouloir omettre les commentaires qui ne sont pas des commentaires doc. (Tout cas d'utilisation qui souhaite conserver les commentaires souhaite également conserver les espaces.)

S'il vous plaît ne le faites pas. J'ai un cas d'utilisation dans lequel je souhaite utiliser (mais pas conserver - ils seront plutôt écrits dans un produit de compilation séparé) des commentaires dans la syntaxe.

Plus précisément, je souhaite créer des macros de traduction qui chargeraient les traductions d'une chaîne à partir d'un ou plusieurs fichiers source distincts et j'aimerais générer une liste de chaînes à traduire en tant que sous-produit dans la version de débogage. Et il doit y avoir un moyen d'inclure des commentaires à émettre dans cette liste (rust-locale/rust-locale#19). Il est donc logique d'utiliser la syntaxe des commentaires et la macro doit les voir.

Je suis d'accord avec les autres points de ce post.

@jan-hudec
Même si nous n'avions pas de TokenKind::Comment , vous pouvez toujours utiliser des commentaires en regardant le contenu des intervalles entre les jetons consécutifs.

Je ne pense pas que nous devrions avoir TokenKind::Comment pour encourager les macros procédurales à ignorer les commentaires afin que les utilisateurs soient libres d'ajouter des commentaires aux invocations de macros sans se soucier de changer la sémantique.

@jan-hudec Y a-t-il une raison pour laquelle les attributs ne fonctionneront pas avec votre solution ?

@abonander , les attributs n'ont absolument aucun sens. Les chaînes traduisibles agissent comme des littéraux, pas comme des éléments. Mais les extraire pendant la compilation serait juste pour plus de commodité - cela peut toujours être fait en tant qu'analyse séparée (et en fait, peut finir par l'être, car j'ai besoin d'en voir _tous_ dans la caisse et la compilation incrémentielle casserait cela).

Je souhaite créer une macro procédurale basée sur la dérivée de serde (et appelle ainsi directement les fonctions de flux de jetons serde), mais il n'y a aucun moyen de dire que je souhaite utiliser la dérivée serde en tant que bibliothèque plutôt que macro procédurale. Ce n'est pas exclusif pour dériver des macros, je peux voir qu'une chose similaire est également recherchée pour les macros procédurales «normales».

Ma seule solution pour le moment semble être de bifurquer serde_derive.

Le problème est ce message d'erreur de rustc :

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

Il est facile de supprimer cela et de le faire fonctionner, mais il y a aussi une certaine complexité que je ne sais pas comment résoudre - une caisse de macro procédurale pourrait vouloir à la fois utiliser le proc-macro dérivé d'une autre caisse de macro procédurale, ainsi que appeler les fonctions pour générer la dérivée pour un utilisateur en aval. A quoi cela ressemblerait-il ? Existe-t-il en ce moment quelque chose de semblable, où une caisse peut être liée de deux manières différentes à la demande de la caisse de consommation ?

@aidanhs

une caisse de macros procédurales pourrait vouloir à la fois utiliser la dérive proc-macro d'une autre caisse de macros procédurales, ainsi qu'appeler les fonctions pour générer la dérive pour un utilisateur en aval. A quoi cela ressemblerait-il ?

Vous ne pouvez pas accéder aux fonctions (ou à quoi que ce soit d'autre que les macros procédurales) à partir d'une caisse proc-macro . Si vous souhaitez utiliser les fonctions TokenStream -> TokenStream et les macros procédurales correspondantes, vous devrez placer les fonctions TokenStream -> TokenStream dans une caisse distincte, non proc-macro , puis disposer une caisse proc-macro qui délègue simplement à ces fonctions.

Cette RFC sera principalement implémentée une fois que le #40939 arrivera.

Fournir un moyen pour les auteurs de proc_macro de créer des extensions qui utilisent des éléments dans une caisse prédéterminée foo sans exiger que l'utilisateur de la macro inclue extern crate foo; à la racine de la caisse

Supposons que je souhaite présenter une seule caisse contenant à la fois des éléments non macro et une macro procédurale faisant référence à ces éléments. Lorsque le #40939 atterrira, ce modèle à trois caisses sera-t-il le moyen idiomatique d'atteindre cet objectif ?

  1. Mettez tous les éléments non macro dans foo_runtime
  2. Implémentez la macro procédurale dans foo_macros , en vous référant aux symboles dans foo_runtime si nécessaire
  3. Ajoutez une caisse "façade" finale foo qui pub use s les articles de foo_runtime et foo_macros

    • C'est la seule caisse que l'utilisateur importera directement

    • Cela fonctionne car le système d'hygiène corrige les macros pour pointer vers la bonne caisse

Je demande parce que mon cas d'utilisation implique l' importation de deux caisses , et ce serait formidable pour la convivialité si je pouvais m'en tirer avec une seule.

@lfairy Je pense qu'un modèle "à deux caisses" sera la manière idiomatique:

  1. Mettez tous les éléments non macro dans foo
  2. Implémentez la macro procédurale dans foo_macros , en vous référant aux symboles dans foo si nécessaire, par exemple
#[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 articles de foo_macros à foo .

Cela fonctionne car le système d'hygiène corrige les macros pour pointer vers la bonne caisse

La réexportation d'une macro procédurale dans une autre caisse n'affecte pas la résolution des noms de la macro procédurale.

@jseyfried : Savez-vous si cette astuce de réexportation fonctionne également avec les

@colin-kiegel
Les caisses dérivées personnalisées ne sont que des caisses de macros proc qui n'ont que des #[proc_macro_derive] s.
Avec #[feature(proc_macro)] , vous pouvez réexporter des dérivés personnalisés dans des caisses ordinaires, tout comme vous pouvez réexporter d'autres macros proc.

@jseyfried Je suis conscient de la situation telle qu'elle est en ce moment, j'ai posé la question parce que je ne pense pas que ce soit l'idéal et j'espérais avoir une discussion à ce sujet. Dans la situation que vous décrivez, « déléguer »/réutiliser aux macros procédurales d'une autre caisse devient une question de convaincre l'auteur de la macro (dans ce cas, serde) de diviser ses macros procédurales en deux caisses. Si je peux appeler des macros procédurales comme des fonctions normales, l'auteur de la caisse en amont n'a même pas besoin de savoir que j'utilise sa caisse.

Cela dit, je reconnais le risque de compatibilité - le tokentree exact généré par une macro devient une partie de l'interface stable, donc si serde change la façon dont ils génèrent Derive dans une version de correctif et que j'ai écrit une macro fragile, mon la macro sera cassée pour chaque nouvel utilisateur de ma caisse (par opposition à une macro fragile dans le cas actuel, où dans le pire des cas, elle ne fonctionnera que pour des entrées spécifiques, mais de manière cohérente).

@jseyfried

Cela retire-t-il foo de la liste de livraison actuelle ? Cela sonne mal (c'est-à-dire qu'il fera quelque chose de particulièrement stupide s'il y a 2 caisses nommées foo liées dans le binaire actuel ?).

@aidanhs Ce serait un changement/ajout de langue majeur qui justifierait sa propre RFC.

@arielb1

Cela retire-t-il foo de la liste de livraison actuelle ? ça sonne mal

Ouais -- malheureusement, les noms extern crate cités ne sont pas hygiéniques, c'est-à-dire que la résolution dépend des noms de caisse qui se trouvent dans la portée où la macro procédurale est utilisée. Nous pouvons atténuer cela en utilisant l'astuce de réexportation (c'est-à-dire réexporter foo_macros dans foo afin que nous sachions que foo sera dans la portée), mais cela ne protège pas contre les erreurs d'ambiguïté lorsqu'il y a deux caisses nommées foo .

Je pense que la meilleure solution ici est d'ajouter des dépendances de phase 1 (c'est-à-dire l'hôte cible par rapport à la cible) aux Cargo.toml pour les caisses proc-macro via un argument de ligne de commande --target-extern . Cela nous permettrait de lister explicitement les noms extern crate dans la portée à l'intérieur de quote! .

@jseyfried

L'idée est qu'une caisse proc-macro aurait une dépendance dans ses métadonnées "cibles", n'est-ce pas ?

@arielb1 Ouais, exactement.

Cette RFC sera principalement implémentée une fois que le #40939 arrivera.

@jseyfried Comme dans, prêt à être stabilisé lorsque ce PR atterrira? Sinon, qu'est-ce qui resterait bloquant la stabilisation ? Je ne veux tout simplement pas que ce soit une autre fonctionnalité où l'on a l'impression que nous arrivons à 95% du chemin vers la mise en œuvre et que les gens sont tout excités, puis que les choses s'arrêtent de manière anticlimatique.

Comme dans, prêt à être stabilisé quand ce PR atterrira ?

Non, nous voulons acquérir une certaine expérience avec l'API avant de stabiliser et peut-être d'une hygiène à l'épreuve du temps pour les noms extern crate (c'est-à-dire résoudre ce problème signalé par @arielb1 ).

Nous voudrons probablement apporter des modifications importantes à cette API ; @eddyb a proposé/envisagé de généraliser OpKind à tous les arbres de jetons. En outre, nous pourrions changer la façon dont nous gérons les commentaires de documentation, les littéraux à virgule flottante, etc. Dans l'ensemble, l'API de ce PR n'est pas encore assez mature pour envisager de se stabiliser pour le moment.

@bstrie malheureusement, la RFC pour accélérer la stabilisation des macros proc (avec une API limitée où, par exemple, les flux de jetons ne sont accessibles que via leur représentation sous forme de chaîne) comme la stabilisation des macros dérivées a échoué : https://github.com/rust-lang/rfcs/ tirer/1913

@ est31 Reporté , plutôt -- après un peu d'expérience avec cette API, nous pourrions nous mettre d'accord sur un sous-ensemble que nous pouvons accepter d'accélérer pour

L'API basée sur String interagit mal avec les macros déclaratives 2.0 et est déjà limitée aujourd'hui, même sans macros 2.0 et juste avec les #[derive] s. Nous voulons éviter autant que possible la prolifération de l'API basée sur String pour éviter les problèmes lorsque les gens migrent vers les macros 2.0.

J'ai ouvert un problème pour #[proc_macro_attribute] apparemment pas développé sur les méthodes de trait (peut-être les éléments de trait en général ?)

Comme il s'agit maintenant du problème de suivi de la caisse proc_macro et de ses nouvelles API, j'ai également pensé écrire quelques réflexions. J'ai publié une caisse appelée proc-macro2 qui est censée être exactement la même que la caisse proc_macro dans l'arborescence, sauf qu'elle offre la possibilité de compiler sur Rust stable. Il a ensuite également la possibilité d'utiliser une fonctionnalité pour compiler sur Rust tous les soirs afin de bénéficier de meilleures informations sur la durée. Cette bibliothèque est destinée à devenir la base d'autres bibliothèques comme syn , et lors du développement de syn nous avons trouvé quelques lacunes que nous souhaiterions peut-être corriger directement dans proc_macro :

  • Il n'y a pas de constructeur Literal pour quelques sortes de littéraux. Ceci est contourné via une chaîne de caractères suivie d'une analyse, mais ce serait formidable de pouvoir les construire directement sans avoir à passer par l'API de chaîne.

    • Cordes brutes - r###" foo "###

    • Chaînes d'octets brutes - rb#" foo "#

    • Littéraux d'octet - b'x'

    • Commentaires sur les documents - ils sont actuellement représentés par le jeton Literal .

  • Il n'y a aucun moyen d'inspecter un Literal et d'en extraire la valeur. À l'heure actuelle, nous nous appuyons sur to_string un littéral et le ré-analyser, mais cette information en théorie est déjà stockée dans le Literal et ce serait bien de pouvoir y accéder.
  • Le mappage des jetons dans certains cas peut être interprété comme un peu étrange. À savoir, en ce moment, les commentaires de la documentation correspondent au type Literal .

Je crois que toutes les autres préoccupations commençant ici ont depuis été résolues.

J'ai rencontré une casse lors du test avec #![feature(proc_macro)] qui affecte les dérivés personnalisés qui ont #[proc_macro_derive(foo, attributes(foo))] . C'est-à-dire, une dérivée personnalisée qui a le nom d'un attribut qui est le même que la dérivée personnalisée. Une de ces caisses est la mienne - dérive-error-chain , qui a #[derive(error_chain)] #[error_chain(...)] struct ErrorKind { ... } . Un autre est dérivé-nouveau, qui a #[derive(new)] #[new] struct S; . Je ne sais pas s'il y en a d'autres.

Pour un code comme celui-ci, le compilateur se plaint au deuxième attribut que "foo" is a derive mode . Est-ce intentionnel ou peut-il être corrigé ? Si c'est intentionnel, je dois me préparer à renommer mon dérivé personnalisé en ErrorChain ou quelque chose du genre.

@Arnavion
C'était intentionnel en général -- puisque les proc_macro_attribute s doivent être développés avant les dérivés, si new étaient proc_macro_attribute alors l'expansion serait ambiguë. Il serait possible d'autoriser spécifiquement new à être un proc_macro_derive , mais je ne suis pas sûr que cela en vaille la peine (cela pourrait également constituer un risque de compatibilité future).

C'était intentionnel en général -- puisque proc_macro_attributes doit être développé avant les dérivés, si new était proc_macro_attribute alors l'expansion serait ambiguë.

D'accord, je vais renommer #[derive(error_chain)] en #[derive(ErrorChain)] .

Il serait possible d'autoriser spécifiquement new à être un proc_macro_derive , mais je ne suis pas sûr que cela en vaille la peine (cela pourrait également être un risque de compatibilité future).

Bien sûr, je ne demandais pas que new soit un cas spécial. C'était juste un exemple de l'un des deux proc_macro_derive s que je connais qui sont brisés par cela.

@Arnavion Désolé, mon dernier commentaire n'était pas le plus clair - je ne voulais pas dire le cas spécial new particulier, mais autoriser #[derive(some_macro)] #[some_attr] struct S; lorsque some_attr résout en un proc_macro_derive . Lorsque some_attr résout en proc_macro_attribute , cela doit être une erreur d'ambiguïté ; aujourd'hui, c'est une erreur d'ambiguïté si some_attr résout en n'importe quelle macro.

Oui je l'ai eu.

( J'espère que c'est le bon endroit pour une question comme celle-ci. )

Quel est le statut de ceci?

  • [ ] Permettre aux auteurs de proc_macro de créer des extensions qui utilisent des éléments dans une caisse prédéterminée foo sans que l'utilisateur de la macro n'inclue extern crate foo; à la racine de la caisse (PR #40939 ).

Le PR a atterri, mais la case n'est toujours pas cochée. @jseyfried a mentionné quelque chose ici et cela semble fonctionner. Cependant, cela ne semble pas du tout fonctionner avec use :

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;
}

Est-ce que j'ai raté quelque chose ? Quelle est la manière idiomatique d'obtenir des symboles use partir d'une caisse externe importée dans la macro ?

Vous ne pouvez pas utiliser use voir https://github.com/rust-lang/rfcs/issues/959. Mais pour une macro, ce n'est pas vraiment un inconvénient d'utiliser le chemin complet à chaque fois. (Sauf pour les traits, je pense)

@parched Merci d'avoir

Dans ma macro, je veux laisser l'utilisateur écrire quelque chose de similaire à un match-matcher. Plus précisément, l'utilisateur écrit un Term et cela peut être une variante d'une énumération ou un simple nom de variable qui lie la valeur de correspondance. Pour écrire du pseudo-code avec la syntaxe macro_rules! :

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

Maintenant, je veux que l'utilisateur puisse simplement spécifier le nom de la variante sans le nom enum. Ainsi, j'insérerais une instruction use my_crate::AnEnum::*; dans le code généré. Mais comme ce n'est pas possible (pour le moment), je dois vérifier par moi-même si le $matcher est une variante de l'énumération ou non.

J'espère que mon explication est compréhensible. Je voulais juste donner un autre cas d'utilisation pour use dans le code généré par les macros.

@LukasKalbertodt Pourriez-vous simplement utiliser my_crate::AnEnum::$matcher => {} dans le match ?
Peu importe, je suis le problème -- je pense que nous aurons besoin de https://github.com/rust-lang/rfcs/issues/959 pour cela.

@jseyfried Non : $matcher peut être soit un nom de variante (auquel cas votre solution fonctionnerait) soit un simple nom de variable comme dans match x { simple_var_name => {} } . Dans ce dernier cas, cela ne fonctionnerait pas AFAICT. (au fait, je voulais juste mentionner un autre cas d'utilisation pour montrer que l'utilisation de use est importante)

@jseyfried

C'était intentionnel en général -- puisque proc_macro_attributes doit être développé avant les dérivés, si new était proc_macro_attribute alors l'expansion serait ambiguë.

D'accord, je vais renommer #[derive(error_chain)] en #[derive(ErrorChain)] .

Il semble que les attributs des dérivés personnalisés entrent également en conflit avec les macros macro_rules , au lieu de les remplacer comme le font les dérivés personnalisés en fonction de l'ordre d'importation. C'est-à-dire que ce code compile :

#![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,
}

Cela correspond au comportement de courant stable Rust, à l'exception que (1) fonctionne dans stable. J'ai même explicitement documenté que les utilisateurs souhaitant utiliser #[macro_use] avec la caisse error-chain devront l'importer avant d' importer derive-error-chain .

Mais même si je renomme le dérivé personnalisé en ErrorChain pour faire fonctionner (1) avec la fonctionnalité proc_macro (qui est déjà un changement décisif pour le code stable) :

#![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,
}

il ne compile toujours pas - l'attribut à (2) génère l'erreur : macro `error_chain` may not be used in attributes car la macro macro_rules apparemment en conflit avec l'attribut enregistré par la dérive personnalisée au lieu d'être remplacée comme dans le premier cas.

Je dois donc renommer à la fois la dérive personnalisée et son attribut. L'attribut est beaucoup plus utilisé (un sur chaque variante de l'énumération) que le dérivé personnalisé (un sur chaque énumération), il s'agit donc d'un changement de rupture plus important que ce à quoi je m'attendais. Je comprends qu'il s'agit d'une situation délicate de ma propre construction (réutiliser le nom de la macro macro_rules pour une dérive personnalisée et son attribut), mais c'est aussi du code qui a été compilé dans stable depuis que les dérives personnalisées ont été stabilisée, je n'avais donc aucune raison de penser que ce serait un problème six mois plus tard.

Est-il possible de faire en sorte que les attributs des dérives personnalisées remplacent les macros macro_rules tout comme les dérives personnalisées remplacent les macros macro_rules ? En fait, je ne vois pas comment il pourrait y avoir une ambiguïté entre eux, mais je suppose que c'est la même raison que lorsqu'une macro macro_rules est importée après une dérive personnalisée du même nom - que toutes les macros sont placées dans le même espace de noms sans considérer de quel type de macro il s'agit.

Existe-t-il un « endroit » moins formel pour parler des macros proc ? Comme un canal IRC #rust-proc-macro ? J'adorerais poser de temps en temps de petites questions sur la fonctionnalité, mais cela me semble mal de spammer ce fil :see_no_evil: Et dans le canal #rust , la plupart des gens n'ont pas travaillé avec proc-macros et en particulier la nouvelle API proc_macro (puisqu'elle est instable et tout). Alors : une idée d'où discuter de ce sujet ?

@LukasKalbertodt #rust-internals , peut-être, ou démarrez simplement un nouveau fil sur /r/rust.

TokenStream::from_str panique lorsqu'il est utilisé en dehors d'une macro procédurale (par exemple dans un script de construction) :

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

Serait-il possible/souhaitable de remplacer cette panique par la création implicite d'une « session » factice ? Ou peut-être ajouter une API publique (avec un chemin vers la stabilisation) pour en créer une ?

Quelqu'un a-t-il consulté la littérature sur les macros d'autres systèmes ? J'aimerais entendre les opinions des gens à ce sujet. Je vais parler de Scheme ici, car c'est ce que je connais le mieux.

Je travaille personnellement à la mise en œuvre de syntax-rules pour le schéma R7RS sur mon propre projet, et j'ai découvert que syntax-case peut constituer la base pour prendre en charge à la fois des systèmes macro non hygiéniques et hygiéniques ( defmacro et syntax-rules ). GNU Guile fait cela. syntax-case également en charge les fenders qui peuvent effectuer une validation de prédicat supplémentaire sur les listes d'objets de syntaxe (ou quelque chose parmi les lignes de TokenStream dans Scheme). Je peux voir que Mark est en cours de travail, et il semble qu'il soit inspiré par Bindings as Sets of Scopes .

De plus, devrions-nous également discuter si le calcul arbitraire au moment de la compilation doit être pris en charge ? Racket adopte en fait une approche "phase" complète des choses, semble-t-il, avec begin-for-syntax permettant les définitions et le calcul (?) Au niveau de la compilation lors de l'expansion des macros. .

Le contrôle de l'hygiène est très possible avec (datum->syntax <thing-to-copy-scope-from> <thing-to-apply-scope-to>) dans Scheme, vous permettant d'échapper à la portée d'une macro et de prendre à la place la portée d'un objet en dehors de la portée immédiate.

Prenez cet exemple dans The Scheme Programming Language, 3e éd. par R. Kent Dybvig (Chez Scheme, maintenant chez Cisco Systems) : http://www.scheme.com/tspl3/syntax.html . L'exemple montre (include "filename.scm") comme une macro syntax-case et permet à l'interpréteur d'utiliser une macro pour configurer le runtime pour lire à partir d'un fichier et continuer l'évaluation. La question plus profonde ici est de savoir si nous voulons qu'un système de macro-macro permette à de telles choses de se produire au moment de l'expansion de la macro et déclenche des calculs au moment de la compilation tels que le déclenchement d'une importation de fichier (bien que cela semble se produire dans la fonctionnalité de compilateur direct, alors peut-être que nous ne voulons pas faire cela).

Quelles devraient être les limites des macros ? J'imagine que Rust, voulant réduire son temps de compilation, veut restreindre l'évaluation au moment de la compilation (et surtout éviter les boucles infinies). Racket a adopté l'approche de la "tour des préparateurs et des expanseurs" avec des phases référencées dans Lisp in Small Pieces. Voulons-nous autoriser des choses comme autoriser l'accès à une API au moment de la compilation pour effectuer des E/S de fichiers et un calcul récursif limité ? Devrions-nous autoriser des choses comme avoir des macros procédurales capables de transformer les spécifications des feuilles de calcul CSV en instructions switch ?

J'aimerais entendre parler d'autres systèmes! J'ai entendu dire que Template Haskell a une approche intéressante avec des types bien définis pour représenter leur AST, et la paresse dans Haskell peut remplacer de nombreuses utilisations de macros pour les structures de contrôle.

Désolé si je dépasse les bornes.

Quelles devraient être les limites des macros ?

Pour les macros aucun fichier . Une macro procédurale est une extension du compilateur. Cela peut prendre un peu de code C++, l'exécuter via clang et ajouter l'objet résultant à la compilation. Cela peut prendre un peu de SQL, interroger la base de données pour trouver le type de résultat correspondant et générer l'ensemble de résultats approprié. Ce sont des cas d'utilisation réels que les gens veulent faire !

Notez que Rust a un autre système de macros. Sa mise à jour a été approuvée en tant que RFC 1584 et la mise en œuvre est suivie par https://github.com/rust-lang/rust/issues/39412.

@VermillionAzure , d'après un rapide coup d'œil aux formulaires Scheme que vous avez référencés :

Le macro_rules , et leur mise à jour selon la RFC 1584 , est similaire à syntax-rules . Si vous avez des suggestions pour les améliorer, https://github.com/rust-lang/rust/issues/39412 est probablement le meilleur endroit pour en discuter.

Les proc-macros, dont traite ce problème, sont comme la forme générale de define-syntax . Et cette RFC ( 1566 ) définissent très intentionnellement ne rien comme syntax-case . Seule une interface pour appeler une fonction pour transformer le flux de jetons.

L'interface est définie de manière à ce que quelque chose comme syntax-case puisse être implémenté dans une caisse séparée (bibliothèque) et l'intention est de le faire de cette façon. Si vous êtes si enclin, n'hésitez pas à jouer. Tout prototype et rapport sur la facilité ou la difficulté d'utilisation de l'API seront certainement les bienvenus.

Je pense que l'idée était de définir des macros comme des fonctions, comme dans lisp, mais d'avoir une macro, qui renvoie la macro, que macro_rules! définit.

Donc ce qui suit serait équivalent :

    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`
}

C'est ainsi que syntax-rules et syntax-case semblent fonctionner dans un schéma.

@VermillionAzure
Est-ce que vous voudriez?

@porky11 Non, cela ne semble pas être le cas. Je voulais juste voir si les macros Scheme seraient une idée pertinente à ajouter à la discussion - il est évident que puisque les macros procédurales sont censées être beaucoup plus puissantes que le système de macros syntax-case dans Scheme, c'est trivial pour implémenter tous les macro-systèmes en termes de puissance arbitraire fournie ici.

@jan-hudec Est-il sage d'autoriser tout calcul arbitraire en tant qu'extension de compilateur sans aucune sorte de garantie de sécurité ? Je suis absolument abasourdi par l'idée que les macros procédurales vont être si puissantes ici, mais est-ce que des utilisateurs potentiels de Rust considéreraient cela comme un inconvénient de l'utilisation de packages ? Je ne suis en aucun cas un expert en sécurité, mais les vulnérabilités des bibliothèques utilisées dans les extensions de compilateur ne pourraient-elles pas facilement être utilisées pour transformer de manière malveillante le compilateur Rust en vecteur d'attaque ? De plus, si des bogues se produisent dans les bibliothèques utilisées dans les macros procédurales (par exemple, une erreur de segmentation déclenchée par un code de bibliothèque C incorrect), cela signifie-t-il que l'erreur de segmentation se produirait et ferait échouer le compilateur sans message d'erreur approprié ?

Y aurait-il un moyen d'encapsuler les erreurs qui se produisent dans les macros procédurales de manière à n'affecter aucune autre partie du compilateur ?

Autre idée : quand les macros procédurales s'exécutent-elles ? Si les macros procédurales peuvent interagir avec du code qui a des effets secondaires qui pourraient être pertinents (par exemple, communiquer avec un serveur externe avec état, muter une base de données SQL externe, obtenir une clé de sécurité pour se connecter à un système externe), cela ne signifie-t-il pas que le l'ordre dans lequel les macros procédurales sont déclenchées par le processus de compilation est-il important ?

Les packages @VermillionAzure Cargo peuvent déjà avoir des scripts de build qui exécutent du code arbitraire au moment de la compilation, donc les macros procédurales n'aggravent pas les choses sur ce front : vous devez déjà faire confiance à vos dépendances. (Cela est quelque peu facilité par le fait que crates.io est immuable/ajout uniquement et que les dépendances ne se mettent pas à jour automatiquement si vous avez un fichier Cargo.lock : vous n'avez besoin de faire confiance qu'à des versions spécifiques.) Et même si les scripts de construction ne l'ont pas fait. existent, vos dépendances peuvent toujours par nature exécuter du code arbitraire au moment de l'exécution. Le temps de compilation est-il bien pire ?

Cette discussion me fait penser à un problème connexe, mais différent.

Supposons qu'un crate définisse deux macros proc : foo!() écrit un fichier temporaire et bar!() lit ce même fichier. Un consommateur de cette caisse invoque à la fois foo!() et bar!() dans le même module. Ensuite, si la compilation réussit ou non, cela dépendra de celui des foo!() ou bar!() est développé en premier. Cet ordre est défini par l'implémentation, et si suffisamment de personnes écrivent du code comme celui-ci, il peut devenir la norme de facto.

Je ne sais pas à quel point c'est un problème. Juste soucieux de savoir si cela conduira à une répétition des manigances de commande du champ struct.

@SimonSapin

Bien que je sois d'accord avec votre position, je dois souligner qu'il existe une différence significative entre l'exécution au moment de la compilation et l'exécution au moment de l'exécution :

Il fournit un modèle de menace différent, car les éléments ont tendance à être compilés une fois, puis déployés sur de nombreuses machines. (par exemple, exploitation de l'inattention du mainteneur plus une lacune de sandbox sur un cluster de construction de distribution Linux.)

@lfairy Oui, c'est exactement le problème que Racket avait il y a plus de dix ans en 2002. Matthew Flatt, le plus grand contributeur à Racket, a créé un article intitulé " Macros composables et compilables : vous le voulez quand ? . R. Kent Dybvig, qui a travaillé sur Chez Scheme, a également écrit un article sur les phases d'évaluation des bibliothèques/modules dans "Implicit Phasing in R6RS Libraries" .

@SimonSapin Le temps de compilation peut potentiellement être bien pire. Si votre compilateur plante de manière aléatoire ou exécute un comportement malveillant déclenché par le compilateur, je parierais que quelqu'un finirait par écrire un énorme article sur Reddit intitulé "Les modules de Rust sont intrinsèquement dangereux" ou quelque chose comme ça.

@VermillionAzure , je n'ai pas lu les articles très attentivement, mais je ne pense pas qu'ils soient pertinents pour la discussion, car les problèmes rencontrés par Rust sont très différents de ceux rencontrés par Scheme.

Dans Scheme, une bibliothèque peut fournir à la fois des fonctions et des macros, de sorte que le compilateur doit trier correctement les fonctions dont il a besoin au moment de la compilation et celles dont il a besoin au moment de l'exécution. Cependant, dans Rust, un crate fournit soit des macros procédurales, soit des fonctions d'exécution, donc cette division est (pour le moment) évidente.

(Notez qu'une caisse fournissant des fonctions d'exécution peut également fournir des macros basées sur des règles (hygiéniques), mais ce sont des mécanismes distincts dans Rust)

Le problème dont parle

@jan-hudec Ouais, je suppose que tu as raison. Mais l'ordre d'évaluation sera certainement important si les effets secondaires sont autorisés au moment de la compilation, à moins que vous ne puissiez garantir qu'un certain module ne produit pas d'effets secondaires. Un module est-il « typable ?

Je pense qu'une macro procédurale "ne devrait probablement pas" avoir d'effets secondaires parce que certains détails (voir ci-dessous) ne sont pas fiables, mais nous n'aurons probablement pas de mécanisme de type système dans le langage pour les forcer à être purement fonctionnel.

Ces détails incluent l'ordre d'exécution et la simultanéité par rapport à d'autres macros proc, et si une macro proc est réexécutée dans une génération incrémentielle. Pour ce dernier, nous pouvons vouloir ajouter quelque chose pour déclarer des dépendances similaires à rerun-if-changed dans les scripts de construction. Et comme le script de construction, ces déclarations peuvent être incomplètes ou boguées. Nous ne pouvons pas empêcher statiquement tous les bogues.

Je pense que nous devrions éviter de garantir quoi que ce soit sur les effets secondaires (c'est-à-dire que les caisses de macros proc ne sont pas autorisées à s'appuyer sur le fonctionnement des effets secondaires, ni sur le fait d'être redéclenchées pour autre chose qu'un changement de code dans le module dans lequel elles sont appliquées ( donc pas d'état global).

Nous pouvons plus tard assouplir cette exigence avec un moyen de spécifier rerun-if-changed et d'autres choses.

(J'ai une proposition de sécurité de macro script/proc de build générale à moitié préparée qui aidera quelque peu ici, mais je ne l'ai pas encore vraiment écrite)

Les macros de proc IMO/dérivations personnalisées doivent être placées dans un environnement en bac à sable sans aucune E/S ou autre connexion vers l'extérieur et être évaluées par miri, peut-être avec un cranelift JIT.

@est31 c'est une bonne idée mais des trucs comme diesel infer_schema ! déjà
existe, bindgen a besoin de lire des fichiers et d'exécuter des programmes, voire d'inclure ! et
env ! utiliser les E/S.

Le 9 novembre 2017 06:19, "est31" [email protected] a écrit :

Les macros/dérivations personnalisées de la procédure IMO doivent être placées dans un environnement en bac à sable
sans aucune E/S ou autre connexion à l'extérieur et être évalué par
miri, peut-être avec un grue JIT.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/rust-lang/rust/issues/38356#issuecomment-343124957 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAC3n5VOPdKBsu81Sp3tp2XlIQ05L865ks5s0t_PgaJpZM4LMWlc
.

Il semble que #40939 et #44528 aient déjà fusionné... @jseyfried pourriez-vous mettre à jour la liste de contrôle ?

@mark-im mis à jour.

Les macros procédurales peuvent-elles générer des macros procédurales ?

@VermillionAzure Je ne l'ai pas essayé, mais je ne vois pas de raison pour laquelle ils ne pourraient pas. Si bien sûr, comme les macros proc générant du code "d'exécution", elles devraient être dans des caisses distinctes de celles où elles sont utilisées.

En syn, nous avons rencontré une limitation de proc_macro::TokenNode aujourd'hui -- les délimiteurs de blocs { ... } sont associés à un seul Span dans le TokenStream d'entrée, il n'y a donc aucun moyen de déclencher un erreur qui pointe uniquement vers la fermeture } . Rustc ne semble pas avoir cette limitation.

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

Les meilleures choses que nous puissions faire dans une macro proc sont de pointer sur le dernier jeton à l'intérieur du bloc, de pointer sur le bloc entier ou de pointer sur le jeton suivant après le bloc, dont aucun n'est vraiment ce que vous voulez pour une erreur comme ci-dessus.

Une solution générale serait que Span::start et Span::end renvoient un Span à LineColumn comme ils le font actuellement, puis exposent un moyen de passer de Span à la première ligne/colonne de span.

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

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

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

Mentionnant @abonander qui a ajouté cette API dans #43604.

faire en sorte que Span::start et Span::end renvoient un Span à 1 caractère au lieu d'un LineColumn comme ils le font actuellement, puis exposent un moyen d'aller de Span à la première ligne/colonne de span.

Cela obligerait Span à adopter le comportement spécial dont les listes délimitées ont besoin, mais ce serait faux pour tous les autres span. En général, ce n'est pas correct. Envisagez d'obtenir un span pour une expression comme foo(hi) en joignant des éléments. Maintenant, vous voulez pointer sur foo et prendre sp.begin() , mais sp.begin() ne pointe que sur le premier caractère de foo .

Je pense que de meilleures solutions seraient d'ajouter deux étendues à proc_macro::TokenNode::Group ou de permettre la création d'étendues arbitraires.

Span::begin types de retour end peuvent cependant devoir changer : https://github.com/rust-lang/rust/pull/43604#issuecomment -327643229

J'essaie d'obtenir Span::def_site() pour résoudre les problèmes par rapport à ce qui est dans la portée de ma macro procédurale. Est-ce que je comprends mal comment cela est censé fonctionner?

Presque le même code fonctionne si j'utilise Span::call_site() et que MySend définis dans le fichier main.rs, ce qui est comme je m'y attendais. Je n'ai pas réussi à le faire fonctionner avec 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`?

Suivi du côté Syn : https://github.com/dtolnay/syn/issues/290.

@dtolnay
Le problème ici est que MySend est importé en phase 0 (c'est-à-dire pour l'architecture hôte lors de la compilation croisée), donc il n'est pas disponible en phase 1 (c'est-à-dire lors de la compilation pour l'architecture cible).

La solution ici est de permettre aux caisses proc-macro d'avoir des dépendances de phase 1 (architecture cible) afin que nous puissions importer les éléments de la phase 1 dans la portée.

Aujourd'hui, une solution de contournement consiste à retourner :

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
    }
} 

Vous pouvez également le construire manuellement, j'utilise juste quote! pour plus de commodité.

Pour des raisons d'hygiène, dummy / std / MySend n'entrera jamais en collision avec quoi que ce soit d'autre dans la portée, donc par exemple, il est sûr d'utiliser cette macro plus d'une fois dans le même module, il est sûr que ident soit "MySend", etc.

Ce problème, ainsi que le besoin et la solution au mod dummy , sont décrits plus en détail dans https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Malheureusement, jusqu'à ce que les dépendances de la phase 1 soient mises en œuvre, ce sera peu ergonomique.

Merci @jseyfried ! Ça marche. Quelques questions de suivi :

  • Dans le code de mon commentaire précédent, si je modifie impl_mysend_for pour générer un impl pour Send au lieu de MySend alors tout se compile. À quoi cela résout-il Send et pourquoi n'at-il pas atteint la distinction phase 0 vs phase 1 ? Est-ce que cela fonctionne intentionnellement ou par accident ?

  • Qu'y a-t-il d'autre dans la portée qui peut être utilisé par mes jetons def_site() , comme Send ?

  • Si MySend doit provenir d'une bibliothèque (comme imaginez que nous dérivons serde::Serialize ) alors l'utilisateur final a toujours besoin de serde dans son Cargo.toml, même si nous ne le faisons pas besoin d'eux pour écrire extern crate serde . Serait-il possible de faire extern crate avec une résolution d'ident def_site() contre Cargo.toml de la macro procédurale, et extern crate avec une résolution d'ident call_site() contre l'en aval Cargo.toml?

Pour les caisses externes, je suppose que les caisses devraient être rendues explicitement disponibles pour la phase 1 par la macro proc.

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

@dtolnay

Dans le code de mon commentaire précédent, si je modifie impl_mysend_for pour générer un impl pour Send au lieu de MySend, alors tout se compile. À quoi l'envoi est-il résolu et pourquoi n'at-il pas atteint la distinction phase 0 vs phase 1 ? Est-ce que cela fonctionne intentionnellement ou par accident ?

Bonne question. À l'heure actuelle, le prélude est dans la portée du site de définition (à moins que la caisse proc-macro ne soit #![no_implicit_prelude] ) et il s'agit d'un accident (dans un certain sens) dû à la distinction phase 0 vs phase 1 comme vous le soulignez .

Cependant, pour l'ergonomie je pense que la phase 1 devrait contenir implicitement std à la racine proc-macro (afin que vous puissiez toujours quote!(use std::...); ) et le prélude pour plus de commodité/ergonomie et puisque ceux-ci sont déjà implicites en phase 0. Il y aura un PR pour ajouter std à la racine en phase 1 bientôt.

Qu'y a-t-il d'autre dans la portée qui peut être utilisé par mes jetons def_site(), comme Send ?

Outre le prélude et (bientôt) std comme indiqué ci - dessus, les seules autres dans le périmètre de la phase 1 sont les macros proc-mêmes ( et non les fonctions proc-macro, qui sont la phase 0).

Par exemple,

#[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
    }
}

Serait-il possible de faire en sorte que la caisse externe avec un ident def_site() se résolve par rapport au Cargo.toml de la macro procédurale, et la caisse externe avec un ident call_site() se résolve contre le Cargo.toml en aval ?

Oui, sauf que je pense qu'une caisse externe avec Span::def_site() devrait se résoudre par rapport aux dépendances de phase 1 (cible) de la macro procédurale Cargo.toml -- les dépendances de phase 0 d'aujourd'hui sont liées aux bibliothèques compilées pour la plate-forme hôte . Étant donné que les dépendances de la phase 1 n'existent pas encore, le nom de la caisse externe se résout de manière non hygiénique, ce qui est ennuyeux comme vous l'avez souligné.

Une fois que nous aurons les dépendances de la phase 1, nous n'aurons plus besoin de citer extern crate s dans chaque extension pour commencer, ce sera donc moins un problème. Cependant, nous devrions toujours le corriger - le plan actuel est d'essayer d'abord de résoudre les dépendances cibles de la caisse proc-macro, puis de revenir à la résolution non hygiénique avec un cycle d'avertissement de faible priorité pour éviter le désabonnement.

Pour les caisses externes, je suppose que les caisses devraient être rendues explicitement disponibles pour la phase 1 par la macro proc.
#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

Intéressant, nous pourrions le mettre en œuvre de cette façon.

Je pensais plutôt que la caisse de phase 1 serait déclarée à la racine de la caisse proc-macro (par exemple #[phase(1)] extern crate foo; ) afin qu'elle soit automatiquement disponible dans toutes les macros proc (par exemple quote!(use foo::bar); ). Étant donné que extern crate est sur le point de disparaître de toute façon, nous pourrions éviter de déclarer complètement les caisses de la phase 1 -- toutes les dépendances cibles de Cargo.toml seraient automatiquement dans la portée à la racine de la caisse proc-macro en phase 1.

Dans mon code, j'ai découvert qu'il me semblait utiliser des étendues à deux fins : pour contrôler la résolution de noms et pour contrôler les messages d'erreur. Ces deux éléments sont-ils inséparablement liés, ou serait-il possible de créer un intervalle qui mélange l'aspect de résolution de nom d'un intervalle avec les emplacements des messages d'erreur de ligne/colonne d'un intervalle différent ? Je m'attends à ce que ce soit un besoin commun.

Pour être plus précis, j'ai un trait introduit dans la portée dans le def_site de mon dérivé personnalisé et je souhaite invoquer des méthodes trait sur les champs de la structure de l'utilisateur. Si le type de champ n'implémente pas le bon trait, je souhaite que le message d'erreur souligne le champ de structure correspondant.

Je peux générer l'appel de méthode avec un span def_site qui compile et s'exécute, mais malheureusement, les messages d'erreur pointent toujours vers l'attribut dérivé comme nous l'avons vu avec les macros 1.1.

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

Ou je peux générer l'appel de méthode avec la même étendue que l'ident ou le type du champ struct, qui affiche les bons soulignements mais ne parvient pas à résoudre le trait dans la portée de mon def_site.

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

Comment puis-je résoudre correctement et afficher les erreurs comme je le souhaite ?

@dtolnay C'est un excellent point, merci.

Je pense que la bonne façon de corriger https://github.com/rust-lang/rust/issues/46489 pourrait être de faire en sorte que les jetons #[derive(…)] générés aient des portées de résolution de nom identiques scope comme définition de type et error-messages-spans à l'invocation de la macro quote! {} qui les a créés.

Quelle est l'histoire de l'hygiène actuellement? J'ai une fonction comme une macro procédurale qui fonctionnait auparavant (il y a 4 mois) mais à partir de rustc 1.24.0-nightly (b65f0bedd 2018-01-01), il se plaint que l'argument ne peut pas être trouvé dans la portée.

Désolé, j'aurais d'abord dû rechercher le suivi des problèmes, il semble que je viens de cliquer sur https://github.com/rust-lang/rust/issues/46489.

J'ai déposé #47311 qui, je crois, bloque actuellement une implémentation correcte de dérive(Deserialize). Les macros procédurales ne peuvent pas construire une structure qui a des champs privés.

En a déposé un autre, #47312 dans lequel l'accès à un champ de structure de tuple sans nom comme self.0 a des exigences différentes sur la durée du jeton . que l'accès à un champ de structure nommé comme self.x .

47311 et #47312 sont corrigés dans #48082 et #48083, respectivement.

J'ai les deux PR ci-dessus en attente d'examen/commentaire.

On dirait que https://github.com/rust-lang/rust/pull/41029 est fait maintenant ?

Ce PR a été abandonné mais relancé et continue d'être travaillé dans #48465. En attente actuellement sur Crater.

@petrochenkov @nrc

En regardant syntax::ext::expand , il apparaît que les proc_macro_attribute sont actuellement pas traités dans plusieurs contextes (non exhaustif) :

  • sur des blocs ( fold_block() est un noop)
  • sur les déclarations/expressions (#41475, #43988)
  • à l'intérieur des blocs extern {} (#48747)

La RFC 1566 ne répertorie pas les types de nœuds AST spécifiques auxquels les macros d'attribut peuvent être appliquées, suggérant qu'elles devraient être applicables à à peu près n'importe quoi. Mais cela pourrait devenir un peu ridicule, nous devons donc établir clairement ce qui doit être traité mais ne le sont pas, et où les attributs ne devraient jamais être autorisés mais pourraient l'être actuellement (#43988)

@abonander l'intention est que les attributs de macro proc puissent être utilisés partout où un attribut régulier peut être et nulle part ailleurs, ce qui devrait, je pense, couvrir tout ce qui précède (bien que certains ne soient pas stables, et si nous stabilisons les macros proc, nous devrions faire attention à ne stabilise que les usages qui sont stables pour les autres attributs).

@nrc est là n'importe où qui énumère ces emplacements car la référence dit seulement que les attributs peuvent être appliqués à n'importe quel élément . Cependant, je suis presque sûr que les attributs lint peuvent également être appliqués aux blocs et aux instructions.

@nrc est là n'importe où qui énumère ces emplacements car la référence dit seulement que les attributs peuvent être appliqués à n'importe quel élément. Cependant, je suis presque sûr que les attributs lint peuvent également être appliqués aux blocs et aux instructions.

Il n'y a pas de doute - il existe une RFC acceptée et un indicateur de fonctionnalité instable pour les attributs sur n'importe quelle expression, mais je pense que nous ne nous sommes stabilisés que sur les instructions et les blocs. La référence est à court de données.

Ce problème:

Contrôle de stabilité (proc-)macros (problème #34079).

est maintenant fermé WRT proc-macros. Mon PR n'a tout simplement pas ajouté de vérification de stabilité pour les macros Macros 2.0, c'est pourquoi le problème est toujours ouvert (bien qu'il devrait probablement s'agir d'un nouveau problème à la place).

@rfcbot fcp fusionner

J'aimerais proposer qu'un sous -

Cela a été discuté en interne récemment avec un certain nombre de problèmes enregistrés par @petrochenkov et qui devraient être corrigés maintenant (mais pas encore tout à fait publiés dans la nuit). Je pense qu'il serait utile de récapituler ici donc c'est concrètement le sous-ensemble qui serait stabilisé.

Rappelez-vous cependant qu'il s'agit d'un sous -

Les macros et le système de modules

Principalement couvert par https://github.com/rust-lang/rust/issues/35896 et maintenant
ayant terminé son FCP, l'idée principale est que vous pouvez utiliser des instructions use pour
importer des macros. Par exemple un code comme celui-ci :

use some_proc_macro_crate::bar;

#[bar]
fn baz() {}

ou

use some_proc_macro_crate::bar;
bar!();

ou même

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

Cela introduit un troisième espace de noms dans Rust (en plus de la valeur/type
espaces de noms), l'espace de noms de la macro. Attributs, macro_rules et procédural
les macros résident toutes dans l'espace de noms maro.

La différence avec le système de module complet est que seul un élément les chemins seront autorisés à invoquermacro .
Par exemple, #[foo::bar] ou ::bar::baz!() ne seront pas autorisés. Cette
la restriction peut être levée un jour, mais c'est une bonne voie conservatrice pour
Commencer avec.

Où l'expansion peut-elle se produire ?

Les attributs ne peuvent être appliqués qu'aux non-modulesarticles .
« éléments » inclut ici des éléments tels que les éléments de trait, les éléments impl et le module étranger
éléments. L'extension du module ne sera pas encore stable en raison de l'hygiène et
ramifications de la mise en œuvre. Il reste à préciser et à stabiliser cela à un
date ultérieure.

Les instructions et les macros d'attributs d'expression ne seront pas encore stables. C'est
principalement en raison de la réelle nécessité d'hygiène au niveau de l'expression (comme
par opposition au niveau de l'article). Ceci est laissé à se stabiliser à une date ultérieure.

Enfin, les macros d'attributs doivent avoir des arguments à l'intérieurdélimiteurs .
Par exemple #[foo] , #[foo(bar)] et #[foo { bar baz ... @ | ^ hello }]
sont des invocations valides. Des appels comme #[foo = "baz"] , #[foo bar] , ou
#[foo ... = ( baz )] ne sera pas initialement stable.

A quoi ressemblent les macros procédurales ?

Comme les dérivés personnalisés, ils sont définis dans des caisses de type caisse de proc-macro .
Les macros et attributs procéduraux sont définis comme suit :

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 {
    // ...
}

Qu'en est-il de l'hygiène ?

Ci-dessus, il a été vu que les attributs personnalisés et les macros ne peuvent être développés que dans
contextes d' éléments , notamment en générant uniquement de nouveaux nœuds AST qui sont des éléments. Cette
signifie que nous n'avons à nous soucier que de l'hygiène de la génération d'un nouvel élément AST
nœuds.

Les nouveaux articles auront la même hygiène que macro_rules! aujourd'hui. Elles vont
pas être hygiénique. Les nouveaux éléments ajoutés à l'AST entreront dans le même espace de noms que
autres éléments du module.

L'API proc_macro .

Afin de permettre tout cela, la surface suivante sera stabilisée pour
la caisse de 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 { ... }

Plus d'informations sur cette API peuvent être trouvées en ligne ou dans l' original RP

Stratégie de test

Les systèmes macros 1.1 et macros 2.0 ont fait l'objet de nombreux dogfoods tout au long de
l'écosystème depuis un certain temps maintenant. Notamment, toute cette proposition est également
largement testé via la version 0.3 de la caisse proc-macro2 comme
ainsi que la caisse de syn . Tout au long des tests, un certain nombre de bogues ont été
identifié et corrigé et le système actuel semble suffisamment solide pour commencer à
stabilisé. (pour ne pas dire que c'est sans bug !)

Le membre de l'équipe @alexcrichton a proposé de fusionner cela. L'étape suivante est l'examen par le reste des équipes taguées :

  • [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] @sansbateaux

Aucune préoccupation actuellement répertoriée.

Une fois qu'une majorité de réviseurs approuvera (et aucun ne s'y opposera), cela entrera dans sa dernière période de commentaires. Si vous repérez un problème majeur qui n'a été soulevé à aucun moment de ce processus, veuillez en parler !

Consultez ce document pour plus d'informations sur les commandes que les membres de l'équipe tagués peuvent me donner.

cc @rust-lang/compiler, je sais que vous êtes également très intéressé par cela et n'hésitez pas à soulever des objections. Si vous avez une objection de blocage, je peux également l'enregistrer pour vous

Il semble qu'en utilisant l'API fournie proposée pour la stabilisation, les macros proc puissent facilement générer toutes sortes de jetons, ou les copier de l'entrée à la sortie, mais ne peuvent pas facilement inspecter un flux de jetons, même à un niveau superficiel. Par exemple, Literal n'implémente pas Eq ou PartialEq . Une raison particulière à cela ? (Et même cela ne permettrait qu'une comparaison avec des valeurs constantes spécifiées, plutôt que d'extraire une valeur et de la traiter dans le code.)

Dans une implémentation de macro proc, étant donné un TokenStream , que peut faire une macro proc pour introspecter un littéral ? Ou, d'ailleurs, extraire la valeur d'un ? N'est-ce tout simplement pas encore pris en charge ? Existe-t-il un plan pour le soutenir à l'avenir?

(Je n'essaie pas de bloquer la stabilisation du sous-ensemble proposé ; j'aimerais simplement mieux comprendre ce sous-ensemble et ses caractéristiques prévues.)

@alexcrichton Les nouveaux articles auront la même hygiène que macro_rules ! fait aujourd'hui. Elles vont
pas être hygiénique. Les nouveaux éléments ajoutés à l'AST entreront dans le même espace de noms que
autres éléments du module.

Je ne fais pas partie de l'équipe principale de Rust et je n'ai pas examiné en profondeur toutes les discussions passées, mais cela me semble vraiment mauvais. Que se passe-t-il si la macro veut générer des éléments d'aide qui ne sont accessibles que par la macro ?

Plutôt que de supprimer l'hygiène, je pense qu'il est préférable d'appliquer une hygiène complète à 100%, mais de fournir aux macros un moyen de désactiver explicitement l' hygiène pour une variable particulière.

@joshtriplett, vous utiliseriez l'

@joshtriplett ouais, comme @dtolnay l'a mentionné, vous utiliseriez Display ce sur quoi une caisse comme literalext est construite. En général, l'API est destinée à être le "minimum strict", pas une API de première classe qui a toutes les cloches et tous les sifflets. Ceux-ci viendront probablement plus tard!

Ce cycle de stabilisation est destiné à être "maximum minimal" dans le sens où il fournit le moins de fonctionnalités pour couvrir tous les cas d'utilisation (aka Display pour Literal et rien d'autre pour l'interpréter ).

@Pauan ce n'est pas génial, oui, mais c'est exactement la même chose que macro_rules! qui est stable depuis des années et fonctionne dans de nombreux contextes différents. Nous voulons permettre une hygiène et un meilleur traitement ici, mais nous ne sommes pas encore tout à fait prêts. Le constructeur Span::call_site() est la clé de voûte ici où, en l'utilisant, vous demandez "pas d'hygiène". Finalement, nous stabiliserons plus d'options.

Malheureusement, "une hygiène complète à 100%" est dans des années, et le but de cette proposition est d'obtenir quelque chose de stable pour Rust 2018

@alexcrichton Le plan est-il donc de le stabiliser maintenant avec un trou d'hygiène, puis quelques époques / époques / éditions corrigent plus tard ce trou d'hygiène ?

Puisque Span::call_site() existe, y a-t-il une raison pour laquelle il ne peut pas avoir une hygiène complète en ce moment ? Est-ce un manque de main-d'œuvre/de temps, ou y a-t-il des préoccupations théoriques/sémantiques qui doivent encore être étoffées dans un RFC ?

@Pauan pour réitérer qu'il n'y a pas de véritable "trou" dans le sens où il existe déjà aujourd'hui. C'est exactement la même histoire d'hygiène avec macro_rules! et dérive personnalisée. Cette proposition est en fait une extension de cela, n'introduisant rien de nouveau.

Compte tenu d'une "histoire d'hygiène parfaite", nous voudrons toujours une forme de retrait. Actuellement, cette option de retrait est de Span::call_site() (effectivement). En stabilisant seulement cela, nous ne stabilisons qu'un mécanisme de retrait pour l'hygiène. Finalement, nous stabiliserons davantage de fonctionnalités pour rendre les articles entièrement hygiéniques si nécessaire.

La stabilisation de l'hygiène est beaucoup plus éloignée. Il y a (pour autant que je sache) des questions de recherche non résolues, ce n'est pas une question de main-d'œuvre.

@dtolnay Ah, je vois. Donc, vous générez du texte puis ré-analysez le texte ? Je suppose que cela fonctionne pour le moment.

cc @rust-lang/compiler, je sais que vous êtes également très intéressé par cela et n'hésitez pas à soulever des objections. Si vous avez une objection de blocage, je peux également l'enregistrer pour vous

J'ai encore quelques points à revoir et un PR avec quelques ajustements d'API proc-macro en cours.

C'est exactement la même histoire d'hygiène avec macro_rules ! et dérive personnalisée.

Bien sûr, mais je pensais que l'un des objectifs était de créer un meilleur système de macros, donc pointer du doigt le système existant (cassé et limité) ne me semble pas très convaincant.

Compte tenu d'une "histoire d'hygiène parfaite", nous voudrons toujours une forme de retrait.

Absolument, mais mon point est que puisqu'il est possible d'utiliser Span::call_site() pour briser l'hygiène (et ainsi gagner la fonctionnalité macro_rules! ) si vous le souhaitez, en le rendant hygiénique par défaut, vous accédez à la fois à l' hygiène et non hygiénique. Alors que s'il se stabilise avec la non-hygiène, alors il est bloqué uniquement avec la non-hygiène.

Finalement, nous stabiliserons davantage de fonctionnalités pour rendre les articles entièrement hygiéniques si nécessaire.

Cela ressemble à un pansement plutôt ennuyeux (et déroutant) : les macros proc seraient hygiéniques dans la plupart des situations (mais pas les éléments), mais vous pouvez alors utiliser une nouvelle fonctionnalité pour opter pour l'hygiène pour les éléments. Est-ce que je comprends bien ?

Il y a (pour autant que je sache) des questions de recherche non résolues, ce n'est pas une question de main-d'œuvre.

D'accord, c'est assez juste. Je comprends le désir d'opportunité et de pragmaticisme. Tant que le plan est d'avoir finalement l' hygiène solide par défaut à une époque plus tard / ère / édition, alors je suis d' accord avec avoir temporairement une mauvaise hygiène. Je ne veux juste pas que nous stabilisions quelque chose que nous regretterons plus tard.

Dans un sens, il est déjà « hygiénique par défaut, » il est juste que la valeur par défaut est pas encore pris en charge. Span::call_site est l'opt-out. :)

@Pauan Pour développer ce que @alexcrichton a dit :

La construction d'un identifiant nécessite un Span , qui contient des informations d'hygiène. (Voir Term::new )

À l'avenir, nous pourrions exposer de nombreuses façons différentes de construire des Span s, qui reflètent différentes options d'hygiène. Mais pour l'instant, nous n'exposerons que Span::call_site qui prend la portée de l'appelant.

De cette façon, nous pouvons éviter de stabiliser l'ensemble du système d'hygiène tout de suite, tout en gardant ouverte la possibilité d'ajouter de l'hygiène plus tard. Je pense que c'est une astuce assez astucieuse pour contourner le problème !

@rpjohnst Donc, vous voulez dire que la seule façon de renvoyer de nouveaux éléments à partir d'une macro proc est d'utiliser Span::call_site ?

Si c'est le cas, cela semble parfait : dans ce cas, l'hygiène peut en effet être ajoutée à l'avenir d'une manière propre et rétrocompatible.

@lfairy Ahhh, je vois, je n'avais pas réalisé qu'il était nécessaire d'utiliser Span::call_site , je pensais qu'il y avait une portée non hygiénique par défaut implicite. Merci pour l'explication! Vous avez raison, c'est une astuce très astucieuse.

En tant que tel, je n'ai plus d'objections.

@alexcrichton

Attributs, macro_rules et procédural
les macros résident toutes dans l'espace de noms maro.

La dernière fois que j'ai vérifié avec #[feature(proc_macro)] , il y avait un changement rétrocompatible dans le code stable pour la caisse de dérive-erreur-chaîne comme décrit ici. D'après la déclaration citée, il semble que cela continuera à être ainsi dans les macros 1.2. Est-ce exact?

@Arnavion oh mon #[derive] .

Il semble que #48644 et #47786 soient terminés. Quelqu'un pourrait-il mettre à jour l'OP?

@alexcrichton Y a- t-il eu une discussion sur l'autorisation d'accéder aux données internes de Literal et de ses amis ? Je comprends qu'ils ne sont plus des énumérations pour des raisons de compatibilité descendante, mais y a-t-il une raison pour laquelle nous ne pouvons pas avoir quelque chose comme ça pour Literal pour commencer :

    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> {}
    }

Nous pourrions même avoir un tas d'impls TryFrom pour les différents sous-types littéraux.

@abonander ça a été discuté ouais mais la conclusion a été de les ajouter plus tard plutôt que de les rendre nécessaires pour la première passe de stabilisation. Ils peuvent être construits sur crates.io avec l'implémentation Display et nous avons de la place pour ajouter le plus tard à l'avenir

:bell: Ceci entre maintenant dans sa dernière période de commentaires , selon l' examen ci-dessus . :cloche:

@alexcrichton
!Send impls !Sync pour les types d'API de macro proc ne sont pas écrits explicitement, mais déduits.
Pour certaines structures (par exemple Op ), l'impl inféré diffère de ce qui est spécifié dans https://github.com/rust-lang/rust/issues/38356#issuecomment -383693017.
Il est probablement logique d'ajouter explicitement les impls.

Oups oui en effet ! J'ai ouvert https://github.com/rust-lang/rust/pull/50453 pour résoudre ce problème

@alexcrichton Nous avons un problème désagréable avec Term::as_str : j'essayais d'esquisser une preuve informelle qu'en raison d'une portée stricte, &'a Term -> &'a str peut être implémenté pour emprunter dans certains internes à portée, et 'a ne peut jamais être plus grand que la portée de l'interne lui-même (ce qui n'a d'importance que si la fonction réussit, c'est-à-dire si elle est appelée dans cette portée pendant laquelle l'interne est en direct).

AFAICT, Term::as_str est valable , mais en supposant seulement que la condition 'a .

Ce qui est confirmé par exemple par thread_local! , car, bien qu'il vous permette d'échapper à la Term , il vous donne des 'a s de très courte durée, qui si Term::as_str réussit, sont strictement plus courts que la portée interne.
En général, la façon dont l'expansion de proc_macro se produit, et parce que Term est thread-local, il y a très peu de moyens d'échapper à Term , et j'ai supposé que thread_local! était effectivement le seul.

Mais Box::leak existe aussi ! C'est toujours instable, mais aujourd'hui, Box::leak(Box::new(term)).as_str() renvoie &'static str . Je me demande s'il y a d'autres abstractions cassées par Box::leak (cc @RalfJung)

OTOH, c'est seulement compliqué parce que Term ne peut pas posséder les données de chaîne, car il s'agit de Copy .
Si nous supprimons le Copy sur Term , nous pourrions garder un Option<Cell<Rc<String>> paresseux là-dedans.

@eddyb oh Term::as_str est prévu pour être supprimé et n'a pas été inclus dans la stabilisation ici, donc ne vous inquiétez pas ! C'est juste comme ça que nous ne cassons pas proc-macro2 , mais une fois que cela se stabilise, nous pouvons publier un changement décisif pour proc-macro2

@eddyb Je ne connais pas le contexte ici, mais Box::leak est justifié dans mon modèle formel. Si vous possédez de la mémoire pour toujours (c'est-à-dire dans une boîte), vous pouvez tout à fait dire qu'elle a une durée de vie.

J'ai quelques questions:

  1. Le quote! ne se stabilise-t-il pas ?
  2. quote! aura-t-il la porte de fonctionnalité proc_macro_non_items appliquée ? Le commit 79630d4fdfc775b241cae0a209edec2687a29f0f l'exige maintenant, mais quote! est toujours marqué #[unstable(feature = "proc_macro" ... .
  3. Des problèmes de suivi seront-ils déposés pour la stabilisation de proc_macro_path_invoc , proc_macro_mod , proc_macro_expr et proc_macro_non_items ?

Question secondaire sans rapport : où quote! implémenté ?

@mjbshaw Sooo histoire amusante : elle est implémentée dans proc_macro::quote .
rustc_metadata prétend que toute caisse nommée proc_macro contient une macro procédurale nommée quote , mais l'implémentation utilisée provient de la proc_macro rustc_metadata liens contre.

J'ai encore quelques points à revoir et un PR avec quelques ajustements d'API proc-macro en cours.

Revoir les relations publiques : https://github.com/rust-lang/rust/pull/50473

Demande de fonctionnalité pour l'API 1.2 : ajoutez un délimiteur pour les chevrons ( < / > ) afin que des choses comme <T> (en fn foo<T>() {} ) soient analysées comme un Group . Ne pas le faire rend l'analyse par exemple des génériques inutilement compliquée.

@mjbshaw Je ne pense pas que cela fonctionnerait au niveau du jeton pour essayer de déterminer si deux < > sont regroupés les uns avec les autres. Par exemple dans l'entrée de macro suivante :

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

Peut-être qu'il s'agit de deux expressions booléennes $A < $B et $C >= $D , ou peut-être qu'il s'agit de génériques dans un alias de type, par exemple étendu à type $A <$B,$C> = $D; .

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

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

J'ai légèrement mis à jour le PO, mais nous avons ce qui me semble être deux bugs potentiels liés à l'hygiène, en fonction de leur résultat :

Pour ceux qui suivent ce fil, l'API est susceptible d'être modifiée par rapport au commentaire FCP d'origine dans https://github.com/rust-lang/rust/pull/50473 proposé par @petrochenkov. Le résumé à ce jour est :

  • Renommez Term::new en Term::ident et validez la saisie
  • Ajoutez Term::lifetime et validez la saisie
  • Ajouter Term::raw_ident et valider la saisie
  • Renommer Op en Punct
  • Valider la saisie sur Punct::new
  • Renommer Op::op en Punct::as_char

Une requête API mineure que je ferais (peut-être dans #50473 -- @petrochenkov) est un moyen d'ajouter des jetons sur un TokenStream. Peut-être:

impl Extend<TokenTree> for TokenStream

Je pense que cela permettrait d'éliminer le type quote::Tokens (qui est essentiellement Vec<TokenTree> ) et de réduire la prolifération de différents types dans l'écosystème qui signifient tous "certains jetons" - suivis en https ://github.com/dtolnay/syn/issues/205.

+1 sur la suggestion ci-dessus de @dtolnay.

La période de commentaires finale, avec une disposition à fusionner , conformément à l' examen ci - terminée .

J'ai deux questions:

  1. Comme déjà demandé ici , qu'en est-il de quote! ? Quelle devrait être la méthode par défaut pour créer le TokenStream final ? Faut-il le faire manuellement ? Ou doit-on utiliser la caisse de quote ? Est-ce que proc_macro::quote! censé être stabilisé à un moment donné dans le futur ?

  2. Ma compréhension est-elle correcte en ce que la différence entre déclarer une macro de type fonction et une macro de type attribut n'est que le nombre d'arguments ? C'est à dire:

    /// 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 seule différence est que l'on prend un TokenStream comme argument, tandis que l'autre en prend deux . N'est-ce pas un peu subtil ? Pourquoi ne pas utiliser #[proc_macro_attribute] et #[proc_macro_function_like] place ? Cela a-t-il été discuté quelque part ? Si c'est le cas, je serais heureux si quelqu'un pouvait lier la discussion.

Merci pour votre travail à ce sujet ! :)

@LukasKalbertodt Les attributs sont actuellement déclarés avec #[proc_macro_attribute] . Je ne sais pas s'il y a une intention délibérée de changer cela ou s'il s'agit d'une faute de frappe dans la proposition du FCP.

Problème : les jetons analysés à partir de chaînes n'obtiennent pas de délais de Span::call_site : https://github.com/rust-lang/rust/issues/50050#issuecomment -390520317.

Je pense que nous devons changer cela et également changer ce que Span::call_site retourne pour corriger les backtraces de macro, le clippy et l'hygiène d'édition pour les jetons utilisant les étendues de site d'appel.

@LukasKalbertodt la quote! dans la caisse proc_macro n'est pas stabilisée dans le cadre de ce FCP, mais la caisse quote sur crates.io s'appuie sur l'API proposée ici. De plus, comme @abonander l'a souligné, les macros d'attributs sont déclarées avec #[proc_macro_attribute] et #[proc_macro] est réservé exclusivement aux macros de style foo!()

#[proc_macro_attribute] ne devrait-il pas être nommé #[proc_attribute_macro] ou #[attribute_proc_macro] ?

@Zoxc Nous avons déjà #[proc_macro_derive] stable, il serait donc étrange de ne pas suivre cela pour les macros d'attributs.

Peut - on obtenir PartialEq<char> et PartialEq<Punct> pour Punct (similaire à Ident de PartialEq mises en œuvre)? Il semble qu'il devrait être assez sûr d'ajouter. Je suis heureux d'écrire le PR, mais je ne veux pas si l'idée est interdite.

@mjbshaw Est-ce que PartialEq<Punct> comparerait également les portées ? PartialEq<char> semble bien, OTOH.

@eddyb PartialEq pour Ident ne compare pas les étendues (je sais qu'il s'agit de la source proc-macro2 et non de la source proc-macro). Je suis ambivalent quant à savoir si les travées sont incluses dans la comparaison, mais je m'attendrais Punct ce que Ident se comportent de la même manière à cet égard. Punct également son propre Spacing , qui, je suppose, serait inclus dans la comparaison (bien que d'autres pensent peut-être différemment).

Je serais bien de ne mettre en œuvre que PartialEq<char> pour Punct pour le moment. PartialEq<Punct> peuvent être hachés plus tard.

@mjbshaw la caisse proc-macro2 a la liberté de ne pas être exactement ce qu'est proc_macro amont et nous donne une certaine liberté pour expérimenter divers réglages. Je soupçonne que si cela fonctionne bien sur crates.io, nous pouvons l'ajouter à proc_macro , mais il est bien sûr rétrocompatible d'ajouter à proc_macro donc nous commençons avec le strict minimum et nous pouvons évoluer à partir de là une fois que c'est stable.

J'ai effectué un travail de triage pour tous les bogues liés aux macros 1.2 . La plupart des bogues peuvent être classés en « bogues sérieux » ou « tous les bogues liés à la portée ». Actuellement, les bogues liés à l'étendue affectent uniquement les messages d'erreur (car l'intention des macros 1.2 n'est pas de changer la résolution). Le bogue restant non lié à l'étendue (alias sérieux) est https://github.com/rust-lang/rust/issues/50050 , pour lequel @petrochenkov a une solution pour .

La classe Gnome a rompu avec les modifications apportées à proc_macro2/syn/quote, ainsi que la porte de fonctionnalité pour générer des modules à partir de macros proc. C'est réglé maintenant, heureusement.

Que dois-je surveiller pour rester au courant des changements dans ce petit écosystème ?

@federicomenaquintero Si vous utilisez des fonctionnalités instables, envisagez d'avoir un travail CI régulier (quotidien, hebdomadaire, tout ce qui fonctionne pour vous) qui compile votre code avec le dernier Nightly et vous avertit en cas d'échec. (Travis-CI prend en charge l'activation d'une telle "tâche cron" dans ses paramètres.)

@SimonSapin merci, c'est une bonne idée. Nous épinglons des versions de ces caisses dans notre Cargo.toml, mais il est peut-être temps de supprimer les numéros de version et de laisser simplement Cargo télécharger la dernière version. Est-ce la bonne façon de procéder ?

@federicomenaquintero C'est de plus en plus hors sujet, donc si vous souhaitez continuer cette discussion, veuillez le faire ailleurs, comme sur IRC ou http://users.rust-lang.org/ , mais la recommandation générale est que les applications (comme par opposition aux bibliothèques) devraient expédier Cargo.lock avec leur code source, qui épingle efficacement les dépendances. Dans Cargo.toml , il est recommandé de déclarer une dépendance comme foo = "1.2.3" , cela signifie implicitement "cette version ou ultérieure, si compatible selon SemVer".

Donc, je viens de rencontrer un problème avec les macros procédurales qui me bloquent dans le développement d'une caisse que je veux faire.

Considérer ce qui suit:

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

Cela ne fonctionne actuellement pas car les fonctionnalités proc_macro et custom_attributes sont requises mais ne peuvent pas être utilisées en même temps. Si je comprends bien, la stabilisation des macros proc éliminerait le besoin des indicateurs de fonctionnalité ?

L'autre chose est que de cette façon, #[my_attribute] pourrait potentiellement générer du code qui empêche l'exécution de #[other_attribute] . Ce qui serait vraiment cool si sur l'attribut "externe", je pouvais enregistrer des attributs internes qui fonctionnent de la même manière que #[derive(Foo)] fonctionnent.

Qu'en est-il du commentaire de @SimonSapin sur la séance mannequin ?

Serait-il possible/souhaitable de remplacer cette panique par la création implicite d'une « session » factice ? Ou peut-être ajouter une API publique (avec un chemin vers la stabilisation) pour en créer une ?

Je pense qu'il serait très utile d'avoir une séance fictive. Écrire un test unitaire pour des caisses proc-macro est pratiquement impossible ou du moins très gênant dans le cas contraire. De plus, il ne s'agit pas seulement de TokenStream::from_str , mais aussi d'autres fonctions nécessitant une session.

@alexcrichton

J'ai effectué un travail de triage pour tous les bogues liés aux macros 1.2. La plupart des bogues peuvent être classés en « bogues sérieux » ou « tous les bogues liés à la portée ».

J'aimerais mettre à niveau https://github.com/rust-lang/rust/issues/50504 vers le statut "sérieux" - le problème de module décrit n'est qu'un symptôme d'un problème plus profond - les ID d'extension pour les macros proc ne sont pas être enregistré correctement. Je ne sais pas quelles autres conséquences cela peut avoir.
Il existe un PR résolvant le problème sous-jacent (https://github.com/rust-lang/rust/pull/51952), mais il y a des régressions par rapport au correctif et je ne les ai pas encore examinés.

J'ai posté un PR pour stabiliser davantage de macros procédurales sur https://github.com/rust-lang/rust/pull/52081

@petrochenkov me semble bien, je commenterai le PR

Je viens de publier un article sur le problème de proc_macro_derive et leur interaction avec le système de noms. Il y a un autre problème avec la façon dont les attributs enfants proc_macro_derive interagissent avec la portée et le nommage, mais il semble plus pertinent d'en parler ici. Étant donné que les chemins dans les attributs ne sont actuellement pas en voie de stabilisation, nous avons la possibilité que #[derive(foo::Parent)] puisse avoir un attribut enfant #[foo::Child] , mais la macro de dérivation n'aurait aucun moyen, à première vue, de identifier si l'attribut enfant est en fait son propre enfant, car il ne peut pas effectuer de recherche de nom. Pour l'instant, je n'ai pas de solution facile, mais je pense que c'est quelque chose qui devrait être sur le radar pour l'avenir des attributs interdépendants ; il n'y a aucune raison pour que les attributs proc_macro_attribute ne veuillent pas interagir d'une manière qui se heurte à des problèmes de recherche similaires.

J'ai essayé de compiler mon projet aujourd'hui, mais quelque chose ne fonctionne pas, ce qui est probablement lié à ce problème. Tous les messages d'erreur avaient le message : "(voir problème #38356)". C'est ainsi que je suis arrivé ici.
J'inclus ici le message d'erreur que j'ai reçu lors de la compilation. J'inclus également mon Cargo.toml.

Je trouve cela très surprenant, car mon projet est épinglé sur une version spécifique de Rust nightly (rustc 1.29.0-nightly (9bd8458c9 2018-07-09)) Qu'est-ce qui aurait pu changer ? Peut-être une bibliothèque mise à jour ?

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

Erreurs de compilation

$ 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`. 

Avez-vous une idée de ce qui a pu se passer et comment y remédier ? Merci!

@realcr pour la caisse proc-macro2 vous pouvez simplement exécuter cargo update et cela devrait faire l'affaire !

@alexcrichton Je ne pense pas que ce soit le problème ici. Je pense plutôt que @realcr a déjà mis proc-macro2 jour proc-macro2-0.4.8 partout. Le problème est plutôt que la version nocturne est corrigée par une version qui n'inclut pas le #52081. J'ai eu le même problème aujourd'hui et je me suis demandé pourquoi proc-macro2 n'avait supprimé que la version mineure. Mais je ne sais pas très bien comment proc-macro2 gère la compatibilité.

@realcr Essayez de mettre à jour votre compilateur nocturne ou appliquez une version proc-macro-2 < 0.4.8 dans votre projet.

@alexcrichton , @LukasKalbertodt : Merci pour la réponse rapide.
Je viens de mettre à jour mon compilateur nocturne vers la dernière version. Cela a éliminé les problèmes de proc-macro-2, mais j'ai eu beaucoup de nouvelles erreurs de compilation. Exemple:

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)

Pour confirmer, ma version actuelle de rustc :

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

Afin de retracer la source du problème, j'ai essayé de compiler l'exemple de base à partir de futures_await mais cela a également cessé de fonctionner. Je vais déposer un problème là-bas afin que nous puissions résoudre ce problème.

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

Parce que vous utilisez la fonction instable.

@realcr votre nouveau problème de compilation n'est pas lié à ce problème, veuillez rester dans le sujet.

@TeXitoi : N'hésitez pas à modifier ou supprimer quoi que ce soit si vous pensez que ce n'est pas pertinent. Je fais de mon mieux pour vous aider, il m'est difficile de savoir ce qui est sur le sujet et ce qui ne l'est pas. Le message d'erreur "(voir le numéro 38356)" est ce qui m'a amené ici.

J'ai essayé de mettre à jour ma version du compilateur et j'ai cette erreur. mon code

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

#[macro_use(eth_abi)]
extern crate pwasm_abi_derive;

et erreur qui dit que je n'ai pas utilisé #![feature(proc_macro)] , mais je l'ai fait !

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, vous voudrez passer de #![feature(proc_macro)] à #![feature(use_extern_macros)] et cela devrait faire l'affaire

Je pense que vous devrez également utiliser le système de modules pour importer des macros procédurales (et assurez-vous d'avoir un compilateur nocturne à jour)

@alexcrichton oui, je viens de comprendre, grâce à l' article . Cependant, cela ne fonctionne toujours pas :

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

Les règles d'importation pour les macros ont également changé ? Ou je ne peux pas comprendre pourquoi il a commencé à se plaindre ici.

@Pzixel qui peut être un bug dans la macro procédurale ou le compilateur, pouvez-vous déposer un problème dédié pour cela ?

Eh bien, je pense que je devrais d'abord réécrire mon code pour qu'il ait au moins l'air de fonctionner :) Pour le moment, ce n'est pas le cas, vous avez beaucoup changé avec cette fonctionnalité. BRB une fois terminé. S'il ne disparaît pas, je crée un problème.

@alexcrichton
Savez-vous quel « prétraitement » est appliqué aux jetons avant qu'ils ne soient transmis à une macro procédurale ?
Je sais que les dérivés ont au moins $crate éliminés et cfg étendus avant d'obtenir des jetons d'entrée (plus les allers-retours à travers les chaînes ne sont pas entièrement sans perte, mais c'est réparable).

Nous devons nous assurer que rien de tout cela ne se produit avec les macros procédurales nouvellement stabilisées et qu'elles obtiennent des jetons d'entrée avec précision (bugs modulo).

@alexcrichton désolé, cargo expand ne fonctionne pas sur cette caisse pour une raison quelconque. Je ne peux pas confirmer si le problème est de mon côté ou du compilateur un. Je continuerai donc à me culpabiliser jusqu'à ce que cette possibilité ne soit pas complètement exclue.

@petrochenkov, l'expansion de proc-macros a été assez bien vérifiée à ce jour, donc je suis beaucoup moins inquiet à ce sujet que les éléments de résolution de nom. Je ne suis pas personnellement au courant du prétraitement, mais je sais qu'il existe un ordre d'expansion où les dérivés s'exécutent en dernier, les cfgs s'exécutent en premier, et sinon c'est principalement itératif.

Je suis d'accord cependant qu'il est bon d'auditer pour !

Peut-être que j'ai raté quelque chose d'évident. Mais, n'y a-t-il aucun moyen d'appeler une fonction, d'utiliser un type, etc. à partir de la caisse proc_macro-defining à partir d'une extension de macro procédurale ? (ou toute autre caisse connue de la caisse proc_macro, FWIW)

Il existe des solutions de contournement , mais AFAIU elles ne fonctionneront pas si la caisse est renommée par l'utilisateur de la macro procédurale.

Les caisses proc-macro créer des caisses qui les utilisent. Ce ne sont pas des dépendances d'exécution. Vous pouvez considérer l'ensemble de la caisse proc-macro comme une sorte de plugin de compilateur, et non comme une bibliothèque "normale".

Ceci est particulièrement visible lors de la compilation croisée : comme les scripts de construction, les proc-macros sont compilées pour la plate-forme hôte, pas celle cible.

@SimonSapin Je suis d'accord avec toi, mais il peut être vraiment utile de déléguer une partie du travail à une fonction fournie par une caisse, même si ce n'est pas la caisse proc-macro (ex. dans mon lien ci-dessus, le X-derive crate tente d'utiliser une fonction de la caisse X ). Parce que sinon, cela signifierait que tout le code généré par proc-macros doit être autonome ou faire des hypothèses sur l'état du site d'appel.

Ensuite, je peux comprendre que rustc n'est pas encore prêt pour ce genre de fonctionnalité (parce que je suppose que cela fonctionnerait mieux sans avoir besoin de séparer proc-macro des caisses non-proc-macro, ce qui semble être quelque part sur le long- terme feuille de route). Mais je me demande, si l'interface actuelle n'utilisant que TokenStreams est stabilisée, sera-t-il possible de moderniser cette fonctionnalité plus tard ? N'aurait-il pas besoin de quelque chose comme un type de jeton PathToBeResolvedFromTopOfGeneratingProcMacroCrate ? (ce qui serait un changement décisif s'il était ajouté plus tard, afaiu)

Il sera peut-être possible de rendre les choses plus flexibles à terme, mais cela semble assez éloigné.

En attendant, si vous êtes un auteur de bibliothèque, pensez à avoir une caisse foo-proc-macros ou foo-derive pour les macros procédurales, et une bibliothèque "normale" foo qui contient le runtime code mais réexporte également les macros procédurales. De cette façon, l'API destinée à l'utilisateur peut être conservée dans une seule caisse. C'est ce que fait serde (dans certaines configurations) https://github.com/serde-rs/serde/blob/v1.0.71/serde/src/lib.rs#L304

Il convient de souligner cependant que cette solution de contournement ne résout toujours pas le problème de l'utilisateur renommant la caisse racine (par exemple, le problème de suivi de serde ).

@Ekleog , le TokenStream est un flux de TokenTree s et chaque TokenTree est associé à Span , qui contient les informations de portée. Sauf qu'il n'y a actuellement aucun moyen de créer une étendue pour une autre étendue que "site d'appel" (ou vide). Fondamentalement, il est nécessaire de trouver un moyen raisonnablement ergonomique de créer des Span référant à une caisse spécifique.

La raison pour laquelle j'ai demandé est que la case n'est pas cochée. Ce serait bien de le cocher alors !

Avec #![feature(proc_macro)] stabilisé, que reste-t-il de ce problème ?

@jan-hudec Oh, je pensais que les Span étaient uniquement destinés au rapport d'erreurs, car les premiers articles de blog mentionnaient une structure Hygiene (ou du même nom) qui jouait ce rôle. J'avais supposé que ceux-ci avaient disparu, et c'était apparemment faux. Merci! :)

Avec #![feature(proc_macro)] stabilisé, que reste-t-il de ce problème ?

Idéalement, de nouveaux problèmes doivent être déposés pour tous les problèmes individuels restants et les fonctionnalités non stabilisées, puis ce problème peut être fermé (de la même manière que pour https://github.com/rust-lang/rust/issues/ 44660).

Oh, je pensais que les spans étaient uniquement destinés au rapport d'erreurs, car les premiers articles de blog mentionnaient une structure d'hygiène (ou du même nom) qui jouait ce rôle. J'avais supposé que ceux-ci avaient disparu, et c'était apparemment faux. Merci! :)

IIUC, les travées sont le principal moyen de suivre le contexte d'hygiène.

@mark-im En quelque sorte. Ils incluent à la fois des informations sur l'emplacement du code source (pour les messages/diagnostics destinés à l'utilisateur) et le contexte syntaxique (c'est-à-dire des informations sur l'hygiène).

Étant donné le nombre de discussions/de trafic généré par ce problème, est-il judicieux de déplacer proc_macro_diagnostic vers son propre problème de suivi ? J'aimerais également découvrir quels sont les bloqueurs pour la stabilisation de cette fonctionnalité et voir si nous pouvons la faire passer. Diesel l'utilise, et c'est génial jusqu'à présent. L'absence de cette fonctionnalité sur stable conduit la communauté à créer des solutions de contournement géniales, comme la dernière version de syn utilisant compile_error! à sa place.

@sgrif J'ai ouvert un tel problème : https://github.com/rust-lang/rust/issues/54140.

Je suis donc intéressant d'aider à stabiliser les méthodes dans Span et la structure LineColumn. Je vais regarder les problèmes ouverts dans le premier commentaire, mais si quelqu'un veut diriger un débutant vers le compilateur dans une direction particulière, je l'apprécierais :+1:

La porte de fonctionnalité proc_macro_gen m'a indiqué ici, mais dans la liste de contrôle en haut, je ne vois rien qui fasse évidemment référence à une (proc_)macro qui génère d'autres définitions de macro. Cela a-t-il été pris en compte (autre que dans la fonctionnalité de porte de rustc) ?

@jjpe il est probablement préférable en ce moment que nous développions des problèmes de suivi dédiés pour ces portes de fonctionnalités, ce problème était en grande partie dédié à la vague initiale de stabilisations

@alexcrichton Je suis parfaitement d' proc_macro_gen , cela m'a renvoyé ici pour n'en trouver qu'une bonne ou aucune mention. C'est un peu étrange pour moi, alors j'ai décidé de le mentionner, au moins.

@xieyuheng À quoi CodeString / Code c'est-à-dire quelle serait sa sémantique ?
Gardez à l'esprit que TokenStream n'est rien de plus que le code source textuellement, sauf comme une série de valeurs symboliques plutôt qu'un texte gênant.

L'API étendue pour TokenStream (avec TokenTree ) est stable en 1.29. L'importation de macros proc de type fonction sera stable dans la version 1.30.

Il semble que depuis rustc 1.30.0-nightly (63d51e89a 2018-09-28) il n'est plus possible de parcourir le code à l'intérieur du module dans un fichier séparé. Si vous traitez mod module; , vous obtenez TokenStream contenant mod module; , WYSIWYG.

Je comprends que cela est nécessaire afin de préserver les durées, l'hygiène et la cohérence avec le code traité. Existe-t-il ou existera-t-il un moyen de travailler avec le contenu des modules dans des fichiers séparés ? Son absence peut être déroutante pour les utilisateurs finaux lorsqu'une refactorisation triviale de l'organisation des modules entraîne un changement dans le comportement des macros.

Ok, ce problème est énorme et est arrivé au point que je ne pense pas qu'il soit trop utile de rester ouvert et de suivre les API. À cette fin, j'ai ouvert https://github.com/rust-lang/rust/pull/54728 qui divise ce problème en un certain nombre de problèmes de suivi plus précis :

À ce stade, je vais fermer ceci, mais si j'ai oublié de séparer d'autres problèmes de suivi, faites-le moi savoir ! Je peux certainement ouvrir d'autres suivis

@alexcrichton Qu'en est-il des sous-attributs pour une macro de type attribut ?
https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541
Y a-t-il un problème pour cela?

@XX
De tels sous-attributs ne doivent pas nécessairement être une caractéristique du langage ?
Dans le cas de derive enregistrement des attributs personnalisés est nécessaire car les macros dérivées ne peuvent pas supprimer les attributs de leur entrée (l'entrée est immuable).
Les macros d'attributs peuvent supprimer #[other_attribute] s de son entrée, de sorte qu'elles n'obtiendront jamais la résolution de nom et ne rapporteront jamais l'erreur "attribut non résolu".

(À côté de ces attributs personnalisés instables hérités classiques mentionnés dans https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541 sont désormais compatibles avec les macros proc.)

@petrochenkov Oui, merci pour la clarification.

Cette page vous a été utile?
0 / 5 - 0 notes