Rust: Tracking-Problem für RFC 1566: Prozedurale Makros

Erstellt am 14. Dez. 2016  ·  184Kommentare  ·  Quelle: rust-lang/rust

Aktueller Status

Dieses Problem wurde zugunsten feinkörnigerer Tracking-Probleme geschlossen

~Aktualisierte Beschreibung ~

Nächste Schritte:

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

    • warten auf krater

  • [ ] Stabilisierung der proc_macro Funktion

Mögliche Stabilisierungs-Showstopper

Originalbeschreibung

RFC .

Dieser RFC schlägt eine Weiterentwicklung des prozeduralen Makrosystems von Rust (auch bekannt als Syntax) vor
Erweiterungen, auch bekannt als Compiler-Plugins). Dieser RFC spezifiziert die Syntax für die Definition
von prozeduralen Makros, eine allgemeine Ansicht ihrer Implementierung im Compiler,
und skizziert, wie sie mit dem Kompilierungsprozess interagieren.

Auf der höchsten Ebene werden Makros durch die Implementierung von Funktionen definiert, die mit gekennzeichnet sind
ein #[macro] Attribut. Makros arbeiten mit einer Liste von Token, die von der . bereitgestellt werden
Compiler und geben eine Liste von Token zurück, durch die die Makroverwendung ersetzt wird. Wir
Bereitstellung von Low-Level-Einrichtungen für den Betrieb mit diesen Token. Höheres Level
Einrichtungen (zB zum Parsen von Token zu einem AST) sollten als Bibliothekskisten existieren.

Roadmap: https://github.com/rust-lang/rust/issues/38356#issuecomment -274377210.


Aufgaben

  • [x] Implementieren Sie #[proc_macro_attribute] (PR #38842).

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

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

  • [x] Implementieren Sie #[proc_macro] (PR #40129).
  • [x] Identifizieren und sammeln Sie Verwendungen von proc_macro_derive s in den InvocationCollector (PR #39391).
  • [x] Unterstützt Makro-erweiterte proc_macro_derive Importe.

    • Zum Beispiel:

#[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!();
  • [ ] Erweitern Sie Elemente, bevor Sie die angewendeten proc_macro_derive s erweitern (PR #48465).
  • [x] Implementieren Sie Warnungen für nicht verwendete #[macro_use] Importe (PR #39060).
  • [x] Refaktorieren Sie den Parser, um Token-Bäume zu verbrauchen (PR #39118).
  • [x] Bereinigen Sie TokenStream in Vorbereitung auf das weitere Refactoring (PR #39173).
  • [x] TokenTree::Sequence entfernen (PR #39419).
  • [x] Verwenden Sie TokenStream s anstelle von Vec<TokenTree> in tokenstream::TokenTree s Delimited Variante (PR #40202).
  • [x] Verwenden Sie Path s und TokenStream s in ast::Attribute s (PR #40346).

    • [x] Unterstützt nichttriviale Pfade in Attribut-/Ableitungsmakros (zB #[foo::bar] , #[derive(foo::Bar)] ).

  • [x] Fügen Sie Hygieneinformationen in alle Token ein, nicht nur Identifikatoren (PR #40597).
  • [x] Implementieren Sie eine minimale API für proc_macro::TokenStream wie im RFC (PR #40939) beschrieben.

    • [x] Fügen Sie Quell- TokenStream s für interpolierte AST-Fragmente in Token::Interpolated Token ein.

    • [x] Fügen Sie ein TokenStream Zitat proc_macro::quote! hinter dem proc_macro Feature-Gate ein.

  • [x] Bieten Sie proc_macro Autoren die Möglichkeit, Erweiterungen zu erstellen, die Elemente in einer vorgegebenen Crate foo ohne dass der Makrobenutzer extern crate foo; in das Crate-Stammverzeichnis einfügen muss (PR # 40939).

    • [ ] Ergonomie verbessern.

  • [ ] Quelle TokenStream s für Artikel im AST einschließen.
  • [ ] Stabilitätsprüfung (Proc-)Makros (Ausgabe #34079).
  • [x] Erlaube dem proc-Makro, ein privates Feld mit einem def_site-Wert zu initialisieren (Problem #47311). (PR-Nr. 48082)
  • [x] Inkonsistenz zwischen dem Zugriff auf das Feld der geschweiften Struktur und der Tupelstruktur im proc-Makro (Problem Nr. 47312). (PR-Nr. 48083)
  • [ ] Stellen Sie std in Phase 1 für Proc-Makro-Root zur Verfügung (Ausgabe #47314).
  • [x] Fehler durch ungültige Syntax in proc_macro::quote! verbessern (Problem #47315).
  • [ ] Inkonsistenz zwischen Display und IntoIterator für einen TokenStream, der ein Modul enthält (Problem #47627).
  • [x] #[cfg_attr] macht .to_string() und TokenStream nicht einverstanden (Problem #48644).
  • [x] Wunschliste für libproc_macro (Checkliste in #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

Hilfreichster Kommentar

Ok, dieses Problem ist massiv und ist so weit gekommen, dass es meiner Meinung nach nicht mehr allzu nützlich ist, weiter offen zu bleiben und APIs zu verfolgen. Zu diesem Zweck habe ich https://github.com/rust-lang/rust/pull/54728 geöffnet, was dieses Problem in eine Reihe feinkörnigerer Tracking-Probleme aufteilt:

An dieser Stelle werde ich dies schließen, aber wenn ich vergessen habe, andere Tracking-Probleme abzutrennen, lass es mich bitte wissen! Ich kann sicherlich noch ein paar Follow-ups eröffnen

Alle 184 Kommentare

cc @nrc @jseyfried

Ich würde mich freuen, wenn #[proc_macro_attribute] bald implementiert wird. Ich habe bereits einen Prototyp und eine Testnutzung, die ich herausgekramt habe, bevor ich gemerkt habe, dass es noch keine Compiler-Unterstützung gibt :unamused: :

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

Aufgaben

(dtolnay edit: die Checkliste nach oben zum OP verschoben)

cc @nrc @petrochenkov @durka @Ralith

@jseyfried Ich bin auf ein Problem

@abonander Alle Makros (Bang, Attribut und Ableitung) teilen sich denselben Namensraum, daher können wir nicht zwei verschiedene Makros mit demselben Namen im selben Bereich verwenden. Wir könnten diese Fehlermeldung jedoch verbessern. Könnten Sie ein Problem melden?

Tut mir leid, dass ich zu spät zur Party komme. Ich bin mit der Anweisung zufrieden, Token anstelle eines AST bereitzustellen, habe jedoch einige Bedenken hinsichtlich der spezifischen TokenStream API, die im RFC vorgeschlagen wird :

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

Es ist nicht klar, ob diese API als vollständiger Plan gedacht war, der beim Zusammenführen des RFC akzeptiert wurde, oder nur ein Beispiel, das später ausgearbeitet werden soll.

Im Allgemeinen scheint dies weit von der "normalen" Rust-Syntax entfernt zu sein, die vom Compiler außerhalb von Makros akzeptiert wird. Während einige Makros eine domänenspezifische Ad-hoc-Sprache analysieren möchten, möchten andere die "eigentliche Rust"-Syntax analysieren und daraus einen Sinn machen.

  1. (Minor) Ich glaube nicht, dass Eof notwendig ist. Ein Iterator wird vermutlich verwendet, um über ein TokenStream iterieren und Iterator::next bereits None , um das Ende der Iteration zu signalisieren.

  2. (Minor) Ich glaube nicht, dass Exclamation , Dollar oder Semicolon notwendig sind. Das Matching auf Punctuation('!') zum Beispiel ist nicht schwieriger.

  3. (Minor) Wie andere in der RFC-PR erwähnt haben, möchten wir möglicherweise Kommentare weglassen, die keine Doc-Kommentare sind. (Jeder Anwendungsfall, der Kommentare beibehalten möchte, möchte wahrscheinlich auch Leerzeichen beibehalten.)

  4. Soweit ich das beurteilen kann, ist noch eine offene Frage, was mit Operatoren mit mehreren Zeichen zu tun ist (die wahrscheinlich jeweils ein einziges Token sein sollten). Eine mögliche Lösung wird in PR-Kommentaren diskutiert, aber anscheinend hat sie es nicht in den RFC-Text geschafft.

  5. Zahlenliterale fehlen. Sollen Makros [Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')] selbst analysieren, um ein Literal auszuwerten? Sie können dafür nicht einmal str::parse::<f32> verwenden, da die akzeptierte Syntax nicht dieselbe ist wie die Rust-Literal-Syntax (die beispielsweise _ in der Mitte haben kann).

    Ich kann mir vorstellen, dass es hier ein Stabilitätsproblem gibt. Können wir neue numerische Typen wie u128 / i128 (und möglicherweise in Zukunft f128 , u256 , …) und ihre Literale einführen, ohne Änderungen an die Token-API? Eine Möglichkeit, dies zu ermöglichen, könnte sein:

    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
    

    Oder vielleicht etwas anderes. Aber ich glaube nicht, dass "so tun, als ob es keine Zahlen gibt" eine gute Möglichkeit ist, dies zu tun.

  6. // Word ist durch Unicode Standard Annex 31 definiert -

    Diese Definition muss genauer sein. UAX 31 spezifiziert ein paar verschiedene Variationen der Bezeichnersyntax, und keine davon wird "Wort" genannt. Aber die Auswahl der genauen Variation, die wir wollen, ist der Grund, warum Nicht-ASCII-Identifikatoren derzeit

    Stattdessen sollte dies meiner Meinung nach als "was auch immer der aktuelle Compiler als Bezeichner oder Schlüsselwort akzeptiert" definiert werden (was sich gemäß #28979 ändern kann). Vielleicht mit einer pub fn is_identifier(&str) -> bool öffentlichen API in libmacro.

  7. Unicode-Strings und Byte-String-Literale teilen sich eine einzige Token-Variante, was meiner Meinung nach falsch ist, da die Speicherdarstellungen ihrer Werte unterschiedliche Typen haben ( str vs [u8] ). Es ist auch nicht klar, ob die text: Symbol Komponente ein wörtlicher Ausschnitt des Quellcodes oder der Wert nach der Auflösung von Backslash-Escapes sein soll. Ich denke, letzteres sollte auf jeden Fall sein. (Zum Vergleich muss Char(char) letzteres sein, da \u{A0} mehr als ein char braucht, um wörtlich darzustellen.)

Eine andere Möglichkeit, Makros auf hoher Ebene zu schreiben, wäre die Verwendung von Lisp-ähnlichen Makros, aber dies würde eine S-Expression-Darstellung für den gesamten Rost benötigen.

@SimonSapin ,

Wie andere in der RFC-PR erwähnt haben, möchten wir möglicherweise Kommentare weglassen, die keine Dokumentkommentare sind. (Jeder Anwendungsfall, der Kommentare beibehalten möchte, möchte wahrscheinlich auch Leerzeichen beibehalten.)

Bitte nicht. Ich habe einen Anwendungsfall, in dem ich Kommentare in der Syntax verwenden möchte (aber nicht beibehalten – sie werden stattdessen in ein separates Kompilierungsprodukt geschrieben).

Insbesondere möchte ich Übersetzungsmakros erstellen, die Übersetzungen eines Strings aus einer oder mehreren separaten Quelldateien laden, und ich möchte eine Liste von Strings generieren, die als Nebenprodukt beim Debug-Build übersetzt werden sollen. Und es muss eine Möglichkeit geben, Kommentare in diese Liste aufzunehmen (rust-locale/rust-locale#19). Daher ist es sinnvoll, die Kommentarsyntax zu verwenden, und das Makro muss sie sehen.

Den anderen Punkten in diesem Beitrag stimme ich zu.

@jan-hudec
Selbst wenn wir kein TokenKind::Comment , könnten Sie dennoch Kommentare verwenden, indem Sie sich den Inhalt der Spannen zwischen aufeinanderfolgenden Token ansehen.

Ich denke, wir sollten nicht TokenKind::Comment , um prozedurale Makros dazu zu bringen, Kommentare zu ignorieren, damit Benutzer Kommentare zu Makroaufrufen hinzufügen können, ohne sich um die Änderung der Semantik kümmern zu müssen.

@jan-hudec Gibt es einen Grund, warum Attribute mit Ihrer Lösung nicht funktionieren?

@abonander , Attribute machen absolut keinen Sinn. Übersetzbare Zeichenfolgen fungieren als Literale, nicht als Elemente. Sie während der Kompilierung zu extrahieren, wäre jedoch nur der Einfachheit halber - es kann immer als separates Parsen durchgeführt werden (und kann tatsächlich so sein, weil ich _alle_ von ihnen in der Kiste sehen muss und eine inkrementelle Kompilierung das zerstören würde).

Ich möchte ein prozedurales Makro erstellen, das auf dem Derive von Serde basiert (und so die Serde-Tokenstream-Funktionen direkt aufruft), aber es gibt keine Möglichkeit zu sagen, dass ich Serde Derive eher als Bibliothek als als prozedurales Makro verwenden möchte. Dies ist nicht ausschließlich zum Ableiten von Makros gedacht, ich kann mir vorstellen, dass Ähnliches auch für 'normale' prozedurale Makros gewünscht wird.

Meine einzige Lösung scheint im Moment darin zu bestehen, serde_derive zu verzweigen.

Das Problem ist diese Fehlermeldung von rustc:

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

Es ist einfach, das zu entfernen und zum Laufen zu bringen, aber es gibt auch eine gewisse Komplexität, bei der ich nicht sicher bin, wie sie gelöst werden soll - eine prozedurale Makro-Kiste könnte plausibelerweise sowohl das proc-Makro verwenden wollen, das von einer anderen prozeduralen Makro-Kiste abgeleitet ist, als auch Aufrufen der Funktionen zum Generieren der Ableitung für einen nachgeschalteten Benutzer. Wie würde das aussehen? Gibt es derzeit so etwas ähnliches, wo eine Kiste auf Wunsch der konsumierenden Kiste auf zwei verschiedene Arten verknüpft werden kann?

@aidanhs

eine prozedurale makro-Crate könnte plausibelerweise sowohl die proc-macro-ableitung von einer anderen prozedural-macro-crate verwenden als auch die Funktionen aufrufen wollen, um die ableitung für einen nachgeschalteten benutzer zu generieren. Wie würde das aussehen?

Von einer proc-macro Kiste aus können Sie nicht auf die Funktionen (oder irgendetwas anderes außer prozeduralen Makros) zugreifen. Wenn Sie TokenStream -> TokenStream Funktionen und die entsprechenden prozeduralen Makros verwenden möchten, müssen Sie die TokenStream -> TokenStream Funktionen in einer separaten, nicht proc-macro Kiste ablegen und haben dann auch eine proc-macro Kiste, die nur an diese Funktionen delegiert.

Dieser RFC wird größtenteils implementiert, sobald #40939 landet.

Bieten Sie proc_macro Autoren die Möglichkeit, Erweiterungen zu erstellen, die Elemente in einer vorgegebenen Crate foo ohne dass der Makrobenutzer extern crate foo; in das Crate-Stammverzeichnis aufnehmen muss

Angenommen, ich möchte eine einzelne Kiste präsentieren, die sowohl Nicht-Makro-Elemente als auch ein prozedurales Makro enthält, das sich auf diese Elemente bezieht. Wenn #40939 landet, wird dieses Drei-Kisten-Muster der idiomatische Weg sein, um dieses Ziel zu erreichen?

  1. Setzen Sie alle Nicht-Makro-Elemente in foo_runtime
  2. Implementieren Sie das prozedurale Makro in foo_macros und beziehen Sie sich foo_runtime Bedarf auf die Symbole in
  3. Füge eine letzte "Fassade"-Kiste foo , die pub use die Gegenstände aus foo_runtime und foo_macros

    • Dies ist die einzige Kiste, die der Benutzer direkt importiert

    • Das funktioniert, weil das Hygienesystem die Makros so fixiert, dass sie auf die richtige Kiste zeigen

Ich frage, weil mein Anwendungsfall das Importieren von zwei Kisten beinhaltet und es für die Benutzerfreundlichkeit großartig wäre, wenn ich mit nur einer davonkommen könnte.

@lfairy Ich denke, ein "Zwei-Kisten" -Muster wird der idiomatische Weg sein:

  1. Setzen Sie alle Nicht-Makro-Elemente in foo
  2. Implementieren Sie das prozedurale Makro in foo_macros und verweisen Sie foo Bedarf auf Symbole in
#[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 Artikel von foo_macros in foo .

Das funktioniert, weil das Hygienesystem die Makros so fixiert, dass sie auf die richtige Kiste zeigen

Das erneute Exportieren eines prozeduralen Makros in eine andere Kiste hat keinen Einfluss auf die Auflösung von Namen aus dem prozeduralen Makro.

@jseyfried : Weißt du, ob dieser Re-Export-Trick auch mit benutzerdefinierten

@colin-kiegel
Benutzerdefinierte Ableitungskisten sind nur Proc-Makrokisten, die zufällig nur #[proc_macro_derive] s haben.
Mit #[feature(proc_macro)] können Sie benutzerdefinierte Ableitungen in gewöhnlichen Crates reexportieren, genau wie Sie andere Proc-Makros reexportieren können.

@jseyfried Mir ist die Situation im Moment bekannt, ich habe die Frage gestellt, weil ich sie nicht für ideal halte und gehofft, eine Diskussion darüber zu führen. In der von Ihnen beschriebenen Situation geht es beim „Delegieren“/Wiederverwenden an die prozeduralen Makros einer anderen Kiste darum, den Makroautor (in diesem Fall Serde) davon zu überzeugen, ihre prozeduralen Makros in zwei Kisten aufzuteilen. Wenn ich prozedurale Makros wie normale Funktionen aufrufen kann, muss der Autor der vorgelagerten Crate nicht einmal wissen, dass ich ihre Crate verwende.

Das heißt, ich die Kompatibilität Gefahr erkennen - die genaue tokentree durch ein Makro erzeugt wird Teil der stabile Schnittstelle, so dass , wenn serde ändert , wie sie erzeugen Derive in einer Patch - Version und ich habe eine fragile Makro geschrieben, meine Makro wird für jeden einzelnen neuen Benutzer meiner Kiste unterbrochen (im Gegensatz zu einem fragilen Makro im aktuellen Fall, bei dem es im schlimmsten Fall nur für bestimmte Eingaben funktioniert, aber konsistent).

@jseyfried

Zieht dies foo aus der aktuellen Frachtablage? Das hört sich schlecht an (dh wird es etwas besonders Dummes tun, wenn 2 Kisten namens foo mit der aktuellen Binärdatei verknüpft sind?).

@aidanhs Das wäre eine große -ergänzung , die einen eigenen RFC rechtfertigen würde.

@arielb1

Zieht dies foo aus der aktuellen Frachtablage? Das hört sich schlecht an

Ja -- leider sind zitierte extern crate Namen nicht hygienisch, dh die Auflösung hängt davon ab, welche Crate-Namen zufällig im Geltungsbereich des prozeduralen Makros liegen. Wir können dies mit dem Re-Export-Trick abschwächen (dh Re-Export von foo_macros in foo damit wir wissen, dass foo im Geltungsbereich sein wird), aber das schützt nicht gegen Mehrdeutigkeitsfehler, wenn zwei Kisten namens foo .

Ich denke, die beste Lösung hier besteht darin, Abhängigkeiten der Phase 1 (dh Ziel bezüglich Host vs. Ziel) zu den Cargo.toml für proc-macro Kisten über ein --target-extern Befehlszeilenargument hinzuzufügen. Dies würde es uns ermöglichen, die extern crate Namen im Geltungsbereich innerhalb von quote! explizit

@jseyfried

Die Idee ist, dass eine Proc-Makro-Kiste eine Abhängigkeit in ihren "Ziel"-Metadaten hat, oder?

@arielb1 Ja, genau.

Dieser RFC wird größtenteils implementiert, sobald #40939 landet.

@jseyfried Wie

Sind Sie bereit, stabilisiert zu werden, wenn diese PR landet?

Nein, wir möchten einige Erfahrungen mit der API sammeln, bevor wir die Hygiene für extern crate stabilisieren und vielleicht zukunftssicher machen (dh dieses Problem angehen, auf das

Wir werden wahrscheinlich grundlegende Änderungen an dieser API vornehmen wollen; @eddyb hat vorgeschlagen/erwogen, OpKind auf alle Token-Bäume zu verallgemeinern. Außerdem könnten wir ändern, wie wir mit Doc-Kommentaren, Gleitkomma-Literalen usw. umgehen. Insgesamt ist die API in dieser PR noch nicht ausgereift genug, um eine Stabilisierung in Erwägung zu ziehen.

@bstrie leider die RFC zu Fast Track proc Makrostabilisierung (mit einer begrenzten api wo zB Token - Streams durch Repräsentation ihrer Zeichenfolge nur zugänglich ist) , wie die Makro derive Stabilisierung ausgefallen: https://github.com/rust-lang/rfcs/ ziehen/1913

@est31 Verschoben, eher so -- nach ein wenig Erfahrung mit dieser API könnten wir uns auf eine Teilmenge einigen, der wir zustimmen können, um schnell zu stabil zu werden.

Die String -basierte API interagiert schlecht mit deklarativen Makros 2.0 und schränkt bereits heute ein, auch ohne Makros 2.0 und nur mit #[derive] s. Wir möchten die Verbreitung der String basierten API so weit wie möglich vermeiden, um Probleme bei der Migration zu Makros 2.0 zu vermeiden.

Ich habe ein Problem für #[proc_macro_attribute] geöffnet, das anscheinend nicht auf Eigenschaftsmethoden erweitert wird (vielleicht Eigenschaftsgegenstände im Allgemeinen?)

Da dies jetzt das Tracking-Problem für die proc_macro Kiste und ihre neuen APIs ist, dachte ich, ich schreibe mir auch ein paar Gedanken dazu. Ich habe eine Crate namens proc-macro2 , die genau die gleiche wie die proc_macro Crate im Baum sein soll, außer dass sie die Möglichkeit bietet, auf stabilem Rust zu kompilieren. Es hat dann auch die Möglichkeit, eine Funktion zum Kompilieren auf nächtlichem Rust zu verwenden, um von besseren Span-Informationen zu profitieren. Diese Bibliothek soll die Grundlage für andere Bibliotheken wie syn , und bei der Entwicklung von syn wir einige Mängel festgestellt, die wir möglicherweise in proc_macro direkt beheben möchten:

  • Es gibt keinen Literal Konstruktor für einige Arten von Literalen. Dies wird durch Stringifizierung gefolgt von Parsing umgangen, aber es wäre großartig, diese direkt erstellen zu können, ohne die String-API durchlaufen zu müssen.

    • Rohe Saiten - r###" foo "###

    • Rohe Byte-Strings - rb#" foo "#

    • Byte-Literale - b'x'

    • Doc-Kommentare – diese werden derzeit als Literal Token dargestellt.

  • Es gibt keine Möglichkeit, ein Literal zu überprüfen und seinen Wert zu extrahieren. Im Moment verlassen wir uns auf literalext crate, um to_string ein Literal zu erstellen und es erneut zu analysieren, aber diese Informationen sind theoretisch bereits in den Literal gespeichert und es wäre schön, dies tun zu können darauf zuzugreifen.
  • Die Zuordnung von Token kann in einigen Fällen als etwas seltsam ausgelegt werden. Nämlich im Moment werden Doc-Kommentare dem Typ Literal .

Ich glaube, alle anderen Bedenken, die hier beginnen, wurden inzwischen ausgeräumt.

Ich traf einen Bruch , wenn sie mit Prüfung #![feature(proc_macro)] , die benutzerdefinierte herleitet betrifft , die haben #[proc_macro_derive(foo, attributes(foo))] . Das heißt, eine benutzerdefinierte Ableitung, die den Namen eines Attributs hat, das mit der benutzerdefinierten Ableitung identisch ist. Eine solche Kiste ist mine-derive-error-chain, die #[derive(error_chain)] #[error_chain(...)] struct ErrorKind { ... } . Ein anderer ist derive-new, der #[derive(new)] #[new] struct S; . Ich weiß nicht, ob es noch andere gibt.

Bei Code wie diesem beschwert sich der Compiler beim zweiten Attribut, dass "foo" is a derive mode . Ist das gewollt oder kann man das beheben? Wenn dies beabsichtigt ist, muss ich mich darauf vorbereiten, mein benutzerdefiniertes Derive in ErrorChain oder so umzubenennen.

@Arnavion
Dies war im Allgemeinen beabsichtigt -- da proc_macro_attribute s vor Ableitungen erweitert werden müssen, wäre die Erweiterung mehrdeutig, wenn new proc_macro_attribute wäre. Es wäre möglich, new ausdrücklich als proc_macro_derive zuzulassen, aber ich bin mir nicht sicher, ob es das wert ist (könnte auch ein Risiko für die zukünftige Kompatibilität darstellen).

Dies war im Allgemeinen beabsichtigt -- da proc_macro_attributes vor Ableitungen erweitert werden muss, wäre die Erweiterung mehrdeutig, wenn new proc_macro_attribute wäre.

Okay, ich werde #[derive(error_chain)] in #[derive(ErrorChain)] umbenennen.

Es wäre möglich, new ausdrücklich als proc_macro_derive zuzulassen, aber ich bin mir nicht sicher, ob es das wert ist (könnte auch ein Risiko für die zukünftige Kompatibilität darstellen).

Sicher, ich habe nicht darum gebeten, dass new in Sonderformate geschrieben werden. Es war nur ein Beispiel von einem der beiden mir bekannten proc_macro_derive s, die dadurch kaputt sind.

@Arnavion Entschuldigung, mein letzter Kommentar war nicht der klarste -- ich meinte nicht den Sonderfall new speziell, sondern #[derive(some_macro)] #[some_attr] struct S; zuzulassen, wenn some_attr in proc_macro_derive . Wenn some_attr in proc_macro_attribute , müsste dies ein Mehrdeutigkeitsfehler sein; heute ist es ein Mehrdeutigkeitsfehler, wenn some_attr in ein Makro aufgelöst wird.

Ja ich habe es verstanden.

( Ich hoffe, das ist der richtige Ort für eine solche Frage. )

Wie ist der Stand davon?

  • [ ] Bieten Sie proc_macro Autoren die Möglichkeit, Erweiterungen zu erstellen, die Elemente in einer vorgegebenen Crate foo ohne dass der Makrobenutzer extern crate foo; in das Crate-Stammverzeichnis aufnehmen muss (PR #40939 .) ).

Die PR ist gelandet, aber das Kästchen ist immer noch nicht angekreuzt. @jseyfried hat hier etwas erwähnt und es scheint irgendwie zu funktionieren. Allerdings scheint es mit use überhaupt nicht zu funktionieren:

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

Verpasse ich etwas? Was ist der idiomatische Weg zu use Symbolen aus einer externen Kiste, die in das Makro importiert wurde?

Sie können use siehe https://github.com/rust-lang/rfcs/issues/959. Aber für ein Makro ist es nicht wirklich von Nachteil, immer den vollqualifizierten Pfad zu verwenden. (Außer Eigenschaften, denke ich)

@parched Danke für das Verlinken dieses anderen Problems. Mein Anwendungsfall war folgender:

In meinem Makro möchte ich den Benutzer etwas schreiben lassen, das einem Match-Matcher ähnelt. Konkret schreibt der Benutzer ein Term und dies kann entweder eine Variante einer Aufzählung oder ein einfacher Variablenname sein, der den Übereinstimmungswert bindet. So schreiben Sie Pseudocode mit der macro_rules! Syntax:

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

Jetzt möchte ich, dass der Benutzer nur den Variantennamen ohne den Enum-Namen angeben kann. Daher würde ich eine use my_crate::AnEnum::*; Anweisung in den generierten Code einfügen. Da dies aber (im Moment) nicht möglich ist, muss ich selbst prüfen, ob $matcher eine Variante der Aufzählung ist oder nicht.

Ich hoffe meine Erklärung ist verständlich. Ich wollte nur einen anderen Anwendungsfall für use in makrogeneriertem Code angeben.

@LukasKalbertodt Könnten Sie einfach my_crate::AnEnum::$matcher => {} in match ?
Egal, ich bin das Problem – ich glaube, dafür brauchen wir https://github.com/rust-lang/rfcs/issues/959 .

@jseyfried Nein: $matcher kann entweder ein Variantenname sein (in diesem Fall würde Ihre Lösung funktionieren) oder ein einfacher Variablenname wie in match x { simple_var_name => {} } . Im letzteren Fall würde es nicht AFAICT funktionieren. (Übrigens, ich wollte nur einen anderen Anwendungsfall erwähnen, um zu zeigen, dass die Verwendung von use wichtig ist)

@jseyfried

Dies war im Allgemeinen beabsichtigt -- da proc_macro_attributes vor Ableitungen erweitert werden muss, wäre die Erweiterung mehrdeutig, wenn new proc_macro_attribute wäre.

Okay, ich werde #[derive(error_chain)] in #[derive(ErrorChain)] umbenennen.

Es scheint, dass Attribute von benutzerdefinierten Ableitungen auch mit macro_rules Makros in Konflikt stehen, anstatt sie zu überschreiben, wie es benutzerdefinierte Ableitungen basierend auf der Importreihenfolge tun. Das heißt, dieser Code kompiliert:

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

Dies entspricht das Verhalten des aktuellen stabilen Rust, mit der Ausnahme , dass (1) funktioniert in stabil. Ich habe sogar explizit dokumentiert, dass Benutzer, die #[macro_use] mit der error-chain Kiste verwenden möchten, diese importieren müssen, bevor sie derive-error-chain importieren.

Aber selbst wenn ich die benutzerdefinierte Ableitung in ErrorChain umbenenne, damit (1) mit der Funktion proc_macro funktioniert (was bereits eine bahnbrechende Änderung für stabilen Code darstellt):

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

es wird immer noch nicht kompiliert - das Attribut bei (2) gibt den Fehler aus: macro `error_chain` may not be used in attributes weil das macro_rules Makro anscheinend mit dem vom benutzerdefinierten Derivat registrierten Attribut kollidiert, anstatt überschrieben zu werden wie im ersten Fall.

Also muss ich sowohl die benutzerdefinierte Ableitung als auch ihr Attribut umbenennen. Das Attribut wird viel häufiger verwendet (eines für jede Variante der Aufzählung) als das benutzerdefinierte Ableiten (eines für jede Aufzählung), daher ist dies eine größere Änderung, als ich erwartet hatte. Ich verstehe, dass dies eine knifflige Situation meiner eigenen Konstruktion ist (Wiederverwendung des Namens des macro_rules Makros für eine benutzerdefinierte Ableitung und seines Attributs), aber dies ist auch Code, der in Stable kompiliert wurde, seit es benutzerdefinierte Ableitungen gab stabilisiert, so dass ich keinen Grund zu der Annahme hatte, dass es sechs Monate später ein Problem sein würde.

Kann es vielleicht so gemacht werden, dass Attribute von benutzerdefinierten Ableitungen macro_rules Makros überschreiben, so wie benutzerdefinierte Ableitungen selbst macro_rules Makros überschreiben? Eigentlich sehe ich keine Mehrdeutigkeit zwischen ihnen, aber ich gehe davon aus, dass dies derselbe Grund ist, als wenn ein macro_rules Makro nach einer benutzerdefinierten Ableitung desselben Namens importiert wird - dass alle Makros in die gleichen Namensraum, ohne zu berücksichtigen, um welche Art von Makro es sich handelt.

Gibt es einen weniger formellen "Ort", um über Proc-Makros zu sprechen? Wie ein #rust-proc-macro IRC-Kanal? Ich würde gerne von Zeit zu Zeit kleine Fragen zu der Funktion stellen, aber es fühlt sich einfach falsch an, diesen Thread zu spammen :see_no_evil: Und im #rust Kanal haben die meisten Leute noch nicht mit Proc-Makros gearbeitet und insbesondere die neue proc_macro API (da sie instabil ist und so). Also: eine Idee, wo man dieses Thema diskutieren kann?

@LukasKalbertodt #rust-internals , vielleicht, oder starte einfach einen neuen Thread auf /r/rust.

TokenStream::from_str gerät in Panik, wenn es außerhalb eines prozeduralen Makros verwendet wird (zum Beispiel in einem Build-Skript):

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

Wäre es möglich/wünschenswert, diese Panik durch das implizite Erstellen einer Dummy-"Sitzung" zu ersetzen? Oder fügen Sie vielleicht eine öffentliche API (mit einem Pfad zur Stabilisierung) hinzu, um eine zu erstellen?

Hat sich jemand Literatur zu Makros von anderen Systemen angeschaut? Ich würde gerne die Meinungen der Leute dazu hören. Ich werde hier über Scheme sprechen, da ich damit am besten vertraut bin.

Ich arbeite persönlich an der Implementierung von syntax-rules für R7RS Scheme in meinem eigenen Projekt und habe festgestellt, dass syntax-case die Grundlage für die Unterstützung sowohl unhygienischer als auch hygienischer Makrosysteme bilden kann ( defmacro und syntax-rules ). GNU Guile tut dies. syntax-case auch Fender, die eine zusätzliche Prädikatsvalidierung für Syntax-Objektlisten durchführen können (oder etwas aus den Zeilen von TokenStream in Scheme). Ich kann sehen, dass an Mark wird, und es sieht so aus, als wäre es von Bindings as Sets of Scopes inspiriert.

Sollten wir auch diskutieren, ob willkürliche Berechnungen zur Kompilierzeit unterstützt werden sollten? Racket verfolgt tatsächlich einen kompletten "Phasen"-Ansatz, wie es scheint, wobei begin-for-syntax Definitionen und Berechnungen (?) auf Kompilierzeit-Ebene während der Makroexpansion ermöglicht. .

Die Kontrolle über die Hygiene ist mit (datum->syntax <thing-to-copy-scope-from> <thing-to-apply-scope-to>) in Scheme sehr gut möglich, sodass Sie den Geltungsbereich eines Makros verlassen und stattdessen einen Geltungsbereich eines Objekts außerhalb des unmittelbaren Geltungsbereichs übernehmen können.

Nehmen Sie dieses Beispiel aus The Scheme Programming Language, 3. Auflage. von R. Kent Dybvig (Chez Scheme, jetzt bei Cisco Systems): http://www.scheme.com/tspl3/syntax.html . Das Beispiel zeigt (include "filename.scm") als syntax-case Makro und ermöglicht dem Interpreter, ein Makro zu verwenden, um die Laufzeit so einzurichten, dass sie aus einer Datei liest und die Auswertung fortsetzt. Die tiefere Frage hier ist, ob wir möchten, dass ein Makro-Makro-System solche Dinge zur Zeit der Makro-Erweiterung zulässt und Berechnungen zur Kompilierzeit auslöst, wie z. vielleicht wollen wir das nicht machen).

Wo sollten die Grenzen von Makros liegen? Ich könnte mir vorstellen, dass Rust, um seine Kompilierungszeit zu verkürzen, die Kompilierzeit-Auswertung einschränken (und insbesondere Endlosschleifen vermeiden möchte). Racket hat den Ansatz des "Turms der Vorbereiter und Expander" mit Phasen verfolgt, wie in Lisp in Small Pieces erwähnt. Wollen wir Dinge wie den Zugriff auf eine API zur Kompilierzeit erlauben, um Datei-E/A und begrenzte rekursive Berechnungen durchzuführen? Sollten wir zulassen, dass prozedurale Makros CSV-Tabellenkalkulationsspezifikationen in switch-Anweisungen umwandeln können?

Ich würde gerne von anderen Systemen hören! Ich habe gehört, dass Template Haskell einen interessanten Ansatz mit wohldefinierten Typen hat, um ihre AST darzustellen, und Faulheit in Haskell kann viele Verwendungen von Makros für Kontrollstrukturen ersetzen.

Tut mir leid, wenn ich aus der Reihe trete.

Wo sollten die Grenzen von Makros liegen?

Für prozedurale Makros, die in dieser Ausgabe behandelt werden, keine . Ein prozedurales Makro ist eine Compiler-Erweiterung. Es kann ein wenig C++-Code benötigen, es durch clang laufen lassen und das resultierende Objekt zur Kompilierung hinzufügen. Es kann etwas SQL erfordern, die Datenbank abfragen, um den entsprechenden Ergebnistyp zu finden und eine geeignete Ergebnismenge zu generieren. Das sind tatsächliche Anwendungsfälle, die die Leute machen wollen!

Beachten Sie, dass Rust ein anderes Makrosystem hat. Das Update wurde als RFC 1584 genehmigt und die Implementierung wird von https://github.com/rust-lang/rust/issues/39412 verfolgt.

@VermillionAzure , ein kurzer Blick auf die

Die macro_rules und ihre Aktualisierung nach RFC 1584 ähneln syntax-rules . Wenn Sie Verbesserungsvorschläge haben, ist https://github.com/rust-lang/rust/issues/39412 wahrscheinlich der beste Ort, um dies zu diskutieren.

Die Proc-Makros, um die es in diesem Thema geht, sind wie die allgemeine Form von define-syntax . Und diese RFC ( 1566 ) ganz bewusst nicht definiert so etwas wie die syntax-case . Nur eine Schnittstelle zum Aufrufen einer Funktion zum Transformieren des Token-Streams.

Die Schnittstelle ist so definiert, dass etwa syntax-case in einer separaten Crate (Bibliothek) implementiert werden kann und dies auch beabsichtigt ist. Wenn Sie dazu geneigt sind, können Sie gerne herumspielen. Sowohl Prototypen als auch Berichte darüber, wie einfach oder schwer die API zu verwenden ist, sind sicherlich willkommen.

Ich denke, die Idee war, Makros wie Funktionen zu definieren, wie in lisp, aber ein Makro zu haben, das das Makro zurückgibt, das macro_rules! definiert.

Folgendes wäre also ä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`
}

So scheinen syntax-rules und syntax-case im Schema zu funktionieren.

@VermillionAzure
Ist das, was Sie möchten?

@porky11 Nein, das scheint nicht so zu sein. Ich wollte nur sehen, ob Scheme-Makros eine relevante Idee für die Diskussion wären -- es ist offensichtlich, dass, da prozedurale Makros viel leistungsfähiger sein sollen als das syntax-case Makrosystem in Scheme, dies trivial ist alle Makrosysteme im Sinne der hier gebotenen willkürlichen Macht zu implementieren.

@jan-hudec Ist es ratsam, beliebige Berechnungen als Compiler-Erweiterung ohne jegliche Sicherheitsgarantie zuzulassen? Ich bin absolut überwältigt von der Idee, dass prozedurale Makros hier so mächtig sein werden, aber würden potenzielle Benutzer von Rust dies als Nachteil bei der Verwendung von Paketen betrachten? Ich bin keineswegs ein Sicherheitsexperte, aber könnten Schwachstellen in Bibliotheken, die in Compiler-Erweiterungen verwendet werden, nicht einfach dazu verwendet werden, den Rust-Compiler böswillig in einen Angriffsvektor zu verwandeln? Wenn außerdem Fehler in Bibliotheken auftreten, die in prozeduralen Makros verwendet werden (z. B. Segfault ausgelöst durch fehlerhaften C-Bibliothekscode), bedeutet dies, dass der Segfault hochlaufen und den Compiler ohne ordnungsgemäße Fehlermeldungen zum Versagen bringen würde?

Gibt es eine Möglichkeit, Fehler, die in prozeduralen Makros auftreten, so zu kapseln, dass sie keine anderen Teile des Compilers beeinträchtigen?

Eine andere Idee: Wann werden prozedurale Makros ausgeführt? Wenn prozedurale Makros mit Code interagieren können, der Nebenwirkungen hat, die relevant sein könnten (z Reihenfolge, in der prozedurale Makros durch den Kompilierungsvorgang ausgelöst werden, ist wichtig?

@VermillionAzure Cargo-Pakete können bereits Build-Skripts enthalten, die zur Kompilierzeit beliebigen Code ausführen, sodass prozedurale Makros die Dinge in dieser Cargo.lock Datei haben: Sie müssen nur bestimmten Versionen vertrauen.) Und selbst wenn Build-Skripte dies nicht tun existieren, können Ihre Abhängigkeiten von Natur aus immer noch beliebigen Code zur Laufzeit ausführen. Ist die Kompilierzeit viel schlechter?

Diese Diskussion lässt mich an ein verwandtes, aber anderes Problem denken.

Angenommen, eine Crate definiert zwei proc-Makros: foo!() schreibt eine temporäre Datei und bar!() liest dieselbe Datei. Ein Konsument dieser Kiste ruft sowohl foo!() als auch bar!() im selben Modul auf. Ob die Kompilierung erfolgreich ist oder nicht, hängt dann davon ab, welches von foo!() oder bar!() zuerst expandiert wird. Diese Reihenfolge ist implementierungsdefiniert, und wenn genügend Leute Code wie diesen schreiben, kann dies de facto zum Standard werden.

Ich bin mir jedoch nicht sicher, wie groß das Problem ist. Ich bin nur besorgt darüber, ob dies zu einer Wiederholung der struct-Feldordnungs-Spielereien führen wird.

@SimonSapin

Obwohl ich Ihrer Position zustimme, sollte ich darauf hinweisen, dass es einen wesentlichen Unterschied zwischen der Ausführung zur Kompilierzeit und der Ausführung zur Laufzeit gibt:

Es bietet ein anderes Bedrohungsmodell, da Dinge dazu neigen, einmal kompiliert und dann auf vielen Computern bereitgestellt zu werden. (z. B. Ausnutzung der Unaufmerksamkeit des Betreuers plus Sandboxing-Mangel in einem Linux-Distributions-Build-Cluster.)

@lfairy Ja, genau dieses Problem hatte Racket vor über einem Jahrzehnt, im Jahr 2002. Matthew Flatt, der größte Mitarbeiter von Racket, hat ein Papier mit dem Titel „Composable and Compilable Macros: You Want it When?“ erstellt . R. Kent Dybvig, der an Chez Scheme mitgearbeitet hat, hat in "Implicit Phasing in R6RS Libraries" auch einen Artikel über Phasen in der Evaluierung von Bibliotheken/Modulen geschrieben.

@SimonSapin Die Kompilierzeit kann möglicherweise viel schlimmer sein. Wenn Ihr Compiler zufällig abstürzt oder bösartiges Verhalten ausführt, das vom Compiler ausgelöst wird, dann würde ich wetten, dass jemand einen riesigen Reddit-Post mit dem Titel "Rust's Modules Are Inherently Unsafe" oder so ähnlich schreiben würde.

@VermillionAzure , ich habe die Artikel nicht sehr sorgfältig gelesen, aber ich glaube nicht, dass sie für die Diskussion relevant sind, da sich die Probleme von Rust stark von den Problemen von Scheme unterscheiden.

In Scheme kann eine Bibliothek sowohl Funktionen als auch Makros bereitstellen, sodass der Compiler richtig aussortieren muss, welche Funktionen er zur Kompilierzeit und welche zur Laufzeit benötigt. In Rust stellt eine Kiste jedoch entweder prozedurale Makros oder Laufzeitfunktionen bereit, so dass diese Aufteilung (vorerst) offensichtlich ist.

(Beachten Sie, dass eine Kiste mit Laufzeitfunktionen auch regelbasierte (hygienische) Makros bereitstellen kann, dies jedoch in Rust separate Mechanismen sind.)

Das Problem, über das @lfairy spricht, ist die Reihenfolge der Ausführung der Expander-Funktionen. In Rust kann die Kompilierung für separate Dateien parallel und möglicherweise inkrementell erfolgen, sodass die Ausführungsreihenfolge der Expander nicht definiert ist. Aber geht einer der beiden Artikel tatsächlich darauf ein? Ich habe es nicht gesehen.

@jan-hudec Ja, ich denke du hast recht. Aber die Reihenfolge der Auswertung ist definitiv von Bedeutung, wenn Nebeneffekte zur Kompilierzeit erlaubt sind, es sei denn, Sie können garantieren, dass ein bestimmtes Modul keine Nebeneffekte erzeugt. Ist ein Modul "typfähig"?

Ich denke, dass ein prozedurales Makro „wahrscheinlich keine“ Nebenwirkungen haben sollte, da man sich auf einige Details (siehe unten) nicht verlassen kann, aber wir werden wahrscheinlich keinen typsystemähnlichen Mechanismus in der Sprache haben, um sie zu einer reinen zu zwingen funktional.

Diese Details umfassen die Reihenfolge der Ausführung und Parallelität im Vergleich zu anderen proc-Makros und ob ein proc-Makro in einem inkrementellen Build erneut ausgeführt wird. Für letzteres möchten wir vielleicht etwas hinzufügen, um Abhängigkeiten ähnlich wie rerun-if-changed in Build-Skripten zu deklarieren. Und wie beim Build-Skript können diese Deklarationen unvollständig oder fehlerhaft sein. Wir können nicht alle Fehler statisch verhindern.

Ich denke, wir sollten vermeiden, irgendetwas über Nebenwirkungen zu garantieren (dh proc-Makro-Crates dürfen sich nicht darauf verlassen, dass Nebenwirkungen funktionieren, noch dürfen sie sich darauf verlassen, dass sie für etwas anderes als eine Codeänderung in dem Modul, in dem sie angewendet werden, erneut ausgelöst werden ( also kein globaler Zustand).

Wir können diese Anforderung später lockern, indem wir die Wiederholung bei Änderung und andere Dinge angeben.

(Ich habe einen halbfertigen allgemeinen Build-Skript-/Proc-Makrosicherheitsvorschlag, der hier etwas helfen wird, aber ich habe ihn noch nicht wirklich verfasst)

IMO-Proc-Makros / benutzerdefinierte Ableitungen sollten in eine Sandbox-Umgebung ohne I/O oder andere Verbindungen nach außen gestellt und von miri ausgewertet werden, möglicherweise mit einem Cranelift-JIT.

@est31 das ist eine nette Idee, aber sowas wie diesel infer_schema! schon
vorhanden ist, muss bindgen Dateien lesen und Programme ausführen, sogar einschließen! und
env! E/A verwenden.

Am 9. November 2017 um 06:19 Uhr schrieb "est31" [email protected] :

IMO-Proc-Makros / benutzerdefinierte Ableitungen sollten in eine Sandbox-Umgebung gestellt werden
ohne I/O oder sonstige Verbindung nach außen und werden ausgewertet durch
miri, vielleicht mit einem Kranlift JIT.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/rust-lang/rust/issues/38356#issuecomment-343124957 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAC3n5VOPdKBsu81Sp3tp2XlIQ05L865ks5s0t_PgaJpZM4LMWlc
.

Es sieht so aus, als ob #40939 und #44528 bereits zusammengeführt wurden... @jseyfried könntest du die Checkliste aktualisieren?

@mark-im aktualisiert.

Können prozedurale Makros prozedurale Makros generieren?

@VermillionAzure Ich habe es nicht ausprobiert, aber ich sehe keinen Grund, warum sie es nicht konnten. Natürlich müssten sie, wie Proc-Makros, die "Laufzeit"-Code generieren, in Kisten getrennt von denen sein, in denen sie verwendet werden.

In syn sind wir heute auf eine Einschränkung von proc_macro::TokenNode gestoßen -- Blocktrennzeichen { ... } sind nur einem Span im Eingabe-TokenStream zugeordnet, daher gibt es keine Möglichkeit, einen Fehler, der nur auf das schließende } . Rustc scheint diese Einschränkung nicht zu haben.

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

Die besten Dinge, die wir in einem proc-Makro tun können, sind auf das letzte Token innerhalb des Blocks zu zeigen, auf den gesamten Block oder auf das nächste Token nach dem Block zu zeigen. Nichts davon ist wirklich das, was Sie für einen Fehler wie oben wollen.

Eine allgemeine Lösung wäre, Span::start und Span::end ein 1-Zeichen Span anstelle eines LineColumn wie sie es derzeit tun, und dann einen Weg aufzuzeigen, um gehe von Span zur ersten Zeile/Spalte von span.

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

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

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

Erwähnen Sie @abonander, der diese API in #43604 hinzugefügt hat.

Lassen Sie Span::start und Span::end ein 1-stelliges Span anstelle einer LineColumn zurückgeben, wie sie es derzeit tun, und legen Sie dann einen Weg offen, um von Span zur ersten Zeile/Spalte von span zu gelangen.

Das würde dazu führen, dass Span das spezielle Verhalten annimmt, das begrenzte Listen benötigen, aber für alle anderen Spans wäre es falsch. Im Allgemeinen ist es nicht richtig. Ziehen Sie in Erwägung, eine Spanne für einen Ausdruck wie foo(hi) indem Sie Sachen verbinden. Jetzt möchten Sie auf foo und sp.begin() , aber sp.begin() nur auf das erste Zeichen von foo .

Ich denke, bessere Lösungen wären das Hinzufügen von zwei Spannen zu proc_macro::TokenNode::Group oder das Erstellen beliebiger Spannen.

Span::begin / end Rückgabetypen müssen sich jedoch möglicherweise ändern: https://github.com/rust-lang/rust/pull/43604#issuecomment -327643229

Ich versuche, Span::def_site() zu bekommen, um die Dinge gegen den Umfang meines prozeduralen Makros aufzulösen. Verstehe ich falsch, wie das funktionieren soll?

Fast der gleiche Code funktioniert, wenn ich Span::call_site() und MySend in der main.rs definiert habe, was ich erwarten würde. Habe es mit def_site() aber nicht zum Laufen bekommen.

#![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`?

Verfolgen Sie dies auf der Syn-Seite: https://github.com/dtolnay/syn/issues/290.

@dtolnay
Das Problem dabei ist, dass MySend in Phase 0 importiert wird (dh für die Host-Architektur beim Cross-Compiling), also in Phase 1 (dh beim Compilieren für die Zielarchitektur) nicht verfügbar ist.

Die Lösung hier besteht darin, proc-Makro-Kisten Abhängigkeiten von Phase 1 (Zielarchitektur) zuzulassen, damit wir Elemente der Phase 1 in den Umfang importieren können.

Heute gibt es eine Problemumgehung:

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

Sie können dies auch manuell erstellen, ich verwende nur quote! Einfachheit halber.

Aus hygienischen Gründen kollidieren dummy / std / MySend niemals mit etwas anderem im Gültigkeitsbereich, so dass es zB sicher ist, dieses Makro mehr als einmal im selben Modul zu verwenden. es ist sicher, dass ident "MySend" ist usw.

Dieses Problem sowie die Notwendigkeit und Lösung des mod dummy werden in https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531 ausführlicher beschrieben.

Bis zur Implementierung von Phase-1-Abhängigkeiten wird dies leider unergonomisch sein.

Danke @jseyfried! Das funktioniert. Einige Folgefragen:

  • Wenn ich im Code in meinem vorherigen Kommentar impl_mysend_for ändere, um ein Impl für Send anstelle von MySend zu generieren, dann wird alles kompiliert. Wofür Send wird das aufgelöst und warum wird die Unterscheidung zwischen Phase 0 und Phase 1 nicht erreicht? Funktioniert das absichtlich oder aus Versehen?

  • Was ist sonst noch im Geltungsbereich, das von meinen def_site() Token verwendet werden kann, wie Send ?

  • Wenn MySend aus einer Bibliothek kommen muss (wie stellen Sie sich vor, wir leiten serde::Serialize ), dann benötigt der Endbenutzer immer noch serde in seiner Cargo.toml, auch wenn wir dies nicht tun Sie müssen extern crate serde schreiben. Wäre es möglich, extern crate mit einer def_site() Ident-Auflösung gegen Cargo.toml des prozeduralen Makros und extern crate mit einer call_site() Ident-Auflösung gegen den Downstream zu machen? Cargo.toml?

Für die externen Crates gehe ich davon aus, dass die Crates vom Proc-Makro explizit für Phase 1 verfügbar gemacht werden müssen.

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

@dtolnay

Wenn ich im Code in meinem vorherigen Kommentar Impl_mysend_for ändere, um ein Impl für Send anstelle von MySend zu generieren, wird alles kompiliert. Zu welchem ​​Send wird dies aufgelöst und warum wird die Unterscheidung zwischen Phase 0 und Phase 1 nicht erreicht? Funktioniert das absichtlich oder aus Versehen?

Gute Frage. Im Moment ist das Präludium an der Definitionsseite im Geltungsbereich (es sei denn, die Proc-Makro-Kiste ist #![no_implicit_prelude] ) und dies ist (in gewisser Weise) ein Unfall aufgrund der Unterscheidung zwischen Phase 0 und Phase 1, wie Sie darauf hinweisen .

Aus Ergonomiegründen denke ich jedoch, dass Phase 1 implizit std am Proc-Makro-Root enthalten sollte (damit Sie immer quote!(use std::...); ) und den Auftakt aus Bequemlichkeit/Ergonomie und da diese bereits implizit sind in Phase 0. Es wird bald eine PR geben, um std an der Wurzel in Phase 1 hinzuzufügen.

Was ist sonst noch im Gültigkeitsbereich, der von meinen def_site()-Token verwendet werden kann, z. B. Send?

Außer dem Präludium und (bald) std wie oben besprochen, sind die einzigen anderen Dinge im Geltungsbereich in Phase 1 die proc-Makros selbst (nicht die proc-macro- Funktionen , die Phase 0 sind).

Zum Beispiel,

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

Wäre es möglich, eine externe Kiste mit einer def_site()-Identifikation gegen die Cargo.toml des prozeduralen Makros und eine externe Kiste mit einer call_site()-Identifikation gegen die nachgelagerte Cargo.toml aufzulösen?

Ja, außer ich glaube, dass eine externe Crate mit Span::def_site() gegen die Phase-1-Abhängigkeiten (Ziel) der Cargo.toml des prozeduralen Makros aufgelöst werden sollte – die heutigen Phase-0-Abhängigkeiten sind mit Bibliotheken verknüpft, die für die Host-Plattform kompiliert wurden . Da Phase-1-Abhängigkeiten noch nicht existieren, löst sich der Name der externen Kiste unhygienisch auf, was, wie Sie bereits erwähnt haben, ärgerlich ist.

Sobald wir Phase-1-Abhängigkeiten haben, müssen wir nicht mehr in jeder Erweiterung extern crate s angeben, sodass dies weniger problematisch ist. Wir sollten es jedoch immer noch beheben – der aktuelle Plan sieht vor, zuerst die Zielabhängigkeiten der Proc-Makro-Kiste aufzulösen und dann auf die unhygienische Lösung mit einem Warnzyklus mit niedriger Priorität zurückzugreifen, um Abwanderung zu vermeiden.

Für die externen Crates gehe ich davon aus, dass die Crates vom Proc-Makro explizit für Phase 1 verfügbar gemacht werden müssen.
#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

Interessant, wir könnten es so umsetzen.

Ich dachte stattdessen, dass die Phase-1-Crate am Proc-Makro-Crate-Wurzel (zB #[phase(1)] extern crate foo; ) deklariert würde, damit sie automatisch in allen Proc-Makros verfügbar wäre (zB quote!(use foo::bar); ). Da extern crate sowieso auf dem Weg ist, könnten wir es vermeiden, die Phase-1-Kisten insgesamt zu deklarieren – alle Zielabhängigkeiten aus der Cargo.toml wären automatisch in der Proc-Macro-Kistenwurzel in Phase 1 im Geltungsbereich.

In meinem Code habe ich festgestellt, dass ich Spans für zwei Zwecke zu verwenden scheine: um die Namensauflösung zu kontrollieren und um Fehlermeldungen zu kontrollieren. Sind diese beiden untrennbar miteinander verbunden, oder wäre es möglich, einen Span zu erstellen, der den Namensauflösungsaspekt eines Spans mit den Zeilen-/Spaltenfehlermeldungspositionen eines anderen Spans vermischt? Ich gehe davon aus, dass dies ein allgemeines Bedürfnis ist.

Genauer gesagt, ich habe eine Eigenschaft in den Geltungsbereich der def_site meiner benutzerdefinierten Ableitung gebracht und möchte Eigenschaftsmethoden für die Felder der Struktur des Benutzers aufrufen. Wenn der Feldtyp nicht das richtige Merkmal implementiert, möchte ich, dass die Fehlermeldung das entsprechende Strukturfeld unterstreicht.

Ich kann den Methodenaufruf mit einem def_site-Span generieren, der kompiliert und ausgeführt wird, aber Fehlermeldungen zeigen leider immer auf das Derive-Attribut, wie wir es bei Makros 1.1 gesehen haben.

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

Oder ich kann den Methodenaufruf mit derselben Spanne wie die ID oder den Typ des Strukturfelds generieren, der die richtigen Unterstreichungen zeigt, aber nicht in das Merkmal im Geltungsbereich meiner def_site aufgelöst wird.

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

Wie kann ich richtig beheben und Fehler so anzeigen, wie ich es möchte?

@dtolnay Das ist ein ausgezeichneter Punkt, danke.

Ich denke, dass der richtige Weg, https://github.com/rust-lang/rust/issues/46489 zu beheben, darin besteht, es so zu gestalten, dass die generierten #[derive(…)] Tokens die gleichen Namensauflösungsspannen haben scope als Typdefinition und error-messages-spans beim quote! {} Makroaufruf, der sie erstellt hat.

Wie sieht es aktuell mit Hygiene aus? Ich habe eine Funktion wie ein prozedurales Makro, das früher funktionierte (vor 4 Monaten), aber ab rustc 1.24.0-nightly (b65f0bedd 2018-01-01) beschwert es sich, dass das Argument nicht im Umfang gefunden werden kann.

Tut mir leid, hätte zuerst den Issue Tracker durchsuchen sollen, es scheint, als hätte ich gerade https://github.com/rust-lang/rust/issues/46489 gefunden.

Ich habe #47311 eingereicht, was meiner Meinung nach derzeit eine korrekte Implementierung von derive (Deserialize) blockiert. Prozedurale Makros können keine Struktur mit privaten Feldern erstellen.

Eine andere, #47312, in der der Zugriff auf ein unbenanntes Tupelstrukturfeld wie self.0 andere Anforderungen an die Spanne des . Tokens hat als der Zugriff auf ein benanntes Strukturfeld wie self.x .

47311 und #47312 sind in #48082 bzw. #48083 festgelegt.

Ich habe die beiden oben genannten PRs, die auf eine Überprüfung / einen Kommentar warten.

Sieht so aus, als wäre https://github.com/rust-lang/rust/pull/41029 jetzt fertig?

Diese PR wurde aufgegeben, aber wiederbelebt und in #48465 weiter bearbeitet. Warte gerade auf Krater.

@petrochenkov @nrc

Wenn man sich syntax::ext::expand , scheint es, dass proc_macro_attribute s derzeit in mehreren Kontexten nicht verarbeitet werden (nicht erschöpfend):

  • auf Blöcken ( fold_block() ist ein Noop)
  • zu Aussagen/Ausdrücken (#41475, #43988)
  • innerhalb von extern {} Blöcken (#48747)

RFC 1566 listet keine spezifischen AST-Knotenarten auf, auf die Attributmakros angewendet werden können, was darauf hindeutet, dass sie auf fast alles anwendbar sein sollten. Aber das könnte ein bisschen lächerlich werden, also sollten wir klar festlegen, was verarbeitet werden muss, aber nicht und wo Attribute niemals erlaubt sein sollten, es aber derzeit sein könnten (#43988)

@abonander die Absicht ist, dass proc- Punkte abdecken sollte (obwohl einige nicht stabil sind, und wenn wir proc-Makros stabilisieren, sollten wir darauf achten, dass nur Verwendungen stabilisieren, die für andere Attribute stabil sind).

@nrc ist überall dort, wo diese Orte aufgezählt werden, weil die Referenz nur besagt, dass Attribute auf jedes Element angewendet werden können. Ich bin mir jedoch fast sicher, dass lint-Attribute auch auf Blöcke und Anweisungen angewendet werden können.

@nrc ist überall dort, wo diese Orte aufgezählt werden, da die Referenz nur besagt, dass Attribute auf jedes Element angewendet werden können. Ich bin mir jedoch fast sicher, dass lint-Attribute auch auf Blöcke und Anweisungen angewendet werden können.

Es gibt kein Afaik - es gibt einen akzeptierten RFC und ein instabiles Feature-Flag für Attribute für jeden Ausdruck, aber ich denke, wir haben uns nur bei Anweisungen und Blöcken stabilisiert. Die Referenz hat keine Daten mehr.

Dieses Problem:

Stabilitätsprüfung (Proc-)Makros (Ausgabe #34079).

ist jetzt geschlossen WRT proc-Makros. Meine PR hat nur keine Stabilitätsprüfung für Macros 2.0-Makros hinzugefügt, weshalb das Problem noch offen ist (obwohl es wahrscheinlich stattdessen nur ein neues Problem sein sollte).

@rfcbot fcp zusammenführen

Ich möchte vorschlagen, dass eine Teilmenge von Makros 2.0 als Makros 1.2 für die Version Rust 1.28 stabilisiert wird. Rust 1.28 kommt jede Nacht am 10. Mai 2018 (~2,5 Wochen nach diesem Schreiben) und wird am 2. August 2018 stabil sein. Ich denke, dass FCP vor dem 10. Mai-Cutoff für 1.27 beendet werden kann, das in die Beta eingeht, aber ich möchte es warten Deaktivieren Sie hier alle Stabilisierungen, bis diese Abschaltung erfolgt ist, und verzögern Sie dies auf die Version 1.28.

Dies wurde kürzlich in den Interna diskutiert, zusammen mit einer Reihe von Problemen, die von @petrochenkov registriert wurden und die jetzt behoben werden sollten (aber noch nicht ganz in der Nacht veröffentlicht werden). Ich denke, es wäre hilfreich, hier eine Zusammenfassung zu machen, damit dies konkret die Teilmenge ist, die stabilisiert würde.

Denken Sie jedoch daran, dass dies eine Teilmenge ist . Fehlende Funktionalität bedeutet hier nicht, dass sie niemals stabilisiert oder aus dem Compiler entfernt wird. Vielmehr wird diese Funktionalität nach diesem vorgeschlagenen Stabilisierungsdurchgang instabil bleiben, um zu einem späteren Zeitpunkt stabilisiert zu werden.

Makros und das Modulsystem

Hauptsächlich abgedeckt von https://github.com/rust-lang/rust/issues/35896 und jetzt
Nachdem Sie den FCP abgeschlossen haben, können Sie use Anweisungen verwenden, um
Makros importieren. Beispielcode wie folgt:

use some_proc_macro_crate::bar;

#[bar]
fn baz() {}

oder

use some_proc_macro_crate::bar;
bar!();

oder auch

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

Dies führt einen dritten Namensraum in Rust ein (zusätzlich zum Wert/Typ
namespaces), den Makro-Namespace. Attribute, macro_rules und prozedurale
Makros befinden sich alle im Maro-Namespace.

Der Unterschied zum ausgewachsenen Modulsystem besteht darin, dass nur ein Element Pfade dürfen aufgerufen werdenMakros .
Zum Beispiel werden #[foo::bar] oder ::bar::baz!() nicht zugelassen. Dies
Beschränkung kann eines Tages aufgehoben werden, aber dies ist ein guter konservativer Weg, um
beginnen mit.

Wo kann man expandieren?

Attribute können nur auf Nicht-Module angewendet werdenArtikel .
"Items" umfasst hier Dinge wie Eigenschaftsgegenstände, Impl-Gegenstände und Fremdmodule
Produkte. Die Modulerweiterung wird aufgrund der Hygiene noch nicht stabil sein und
Umsetzungswirkungen. Es bleibt übrig, dies bei a . zu spezifizieren und zu stabilisieren
späteren Zeitpunkt.

Anweisungen und Makros für Ausdrucksattribute werden noch nicht stabil sein. Das ist
vor allem aufgrund der wirklichen Notwendigkeit der Hygiene auf der Ebene des Ausdrucks (wie
im Gegensatz zur Artikelebene). Dies soll sich zu einem späteren Zeitpunkt stabilisieren.

Schließlich müssen Attributmakros Argumente enthaltenTrennzeichen .
Zum Beispiel #[foo] , #[foo(bar)] und #[foo { bar baz ... @ | ^ hello }]
sind gültige Aufrufe. Aufrufe wie #[foo = "baz"] , #[foo bar] oder
#[foo ... = ( baz )] wird zunächst nicht stabil sein.

Wie sehen prozedurale Makros aus?

Wie benutzerdefinierter Ableitung werden sie in proc-macro Kisten-Kisten definiert.
Prozedurale Makros und Attribute werden wie folgt definiert:

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

Was ist mit Hygiene?

Oben wurde gesehen, dass benutzerdefinierte Attribute und Makros nur erweitert werden können in
Elementkontexte , insbesondere nur das Generieren neuer AST-Knoten, die Elemente sind. Dies
bedeutet, dass wir uns nur um die Hygiene bei der Generierung neuer AST-Artikel kümmern müssen
Knoten.

Neue Artikel haben dieselbe Hygiene wie heute macro_rules! . Sie werden
nicht hygienisch sein. Neue Elemente, die dem AST hinzugefügt werden, werden in denselben Namensraum aufgenommen wie
andere Elemente im Modul.

Die proc_macro API.

Um all dies zu ermöglichen, wird die folgende Fläche stabilisiert für
die proc_macro Kiste:

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

Weitere Informationen zu dieser API finden Sie online oder im Original PR

Teststrategie

Die Macros 1.1- und Macros 2.0-Systeme wurden durchgängig umfangreich mit Dogfood versehen
das Ökosystem schon seit geraumer Zeit. Insbesondere dieser gesamte Vorschlag ist auch
ausführlich getestet durch die Version 0.3 der proc-macro2 Kiste als
sowie die syn Kiste . Während des Tests wurden eine Reihe von Fehlern festgestellt
identifiziert und behoben und das aktuelle System fühlt sich solide genug an, um damit zu beginnen
stabilisiert. (um nicht zu sagen, dass es fehlerfrei ist!)

Teammitglied @alexcrichton hat vorgeschlagen, dies zusammenzuführen. Der nächste Schritt ist die Überprüfung durch den Rest der markierten Teams:

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

Derzeit keine Bedenken aufgeführt.

Sobald eine Mehrheit der Gutachter zustimmt (und keine Einwände erheben), tritt die letzte Kommentarfrist ein. Wenn Sie ein wichtiges Problem entdecken, das zu keinem Zeitpunkt in diesem Prozess angesprochen wurde, melden Sie sich bitte!

In diesem Dokument finden Sie Informationen darüber, welche Befehle mir markierte Teammitglieder geben können.

cc @rust-lang/compiler, ihr alle, die ich kenne, interessiert sich auch sehr dafür und könnt gerne Einwände vorbringen. Wenn Sie einen Sperrwiderspruch haben, kann ich diesen auch für Sie registrieren

Es sieht so aus, als ob Proc-Makros mit der bereitgestellten API, die zur Stabilisierung vorgeschlagen wird, problemlos alle Arten von Token generieren oder sie von der Eingabe zur Ausgabe kopieren können, aber einen Strom von Token nicht einmal oberflächlich untersuchen können. Literal implementiert beispielsweise nicht Eq oder PartialEq . Ein besonderer Grund dafür? (Und selbst das würde nur den Vergleich mit angegebenen konstanten Werten ermöglichen, anstatt einen Wert zu extrahieren und im Code zu verarbeiten.)

Was kann ein proc-Makro innerhalb einer proc-Makroimplementierung bei gegebenem TokenStream tun, um ein Literal zu untersuchen? Oder extrahieren Sie den Wert von eins? Wird das einfach noch nicht unterstützt? Ist eine zukünftige Unterstützung geplant?

(Ich versuche nicht, die Stabilisierung der vorgeschlagenen Teilmenge zu blockieren; ich möchte nur diese Teilmenge und ihre beabsichtigten Funktionen besser verstehen.)

@alexcrichton Neue Artikel haben dieselbe Hygiene wie macro_rules! tut heute. Sie werden
nicht hygienisch sein. Neue Elemente, die dem AST hinzugefügt werden, werden in denselben Namensraum aufgenommen wie
andere Elemente im Modul.

Ich gehöre nicht zum Rust-Kernteam und habe mir nicht alle Diskussionen in der Vergangenheit gründlich angesehen, aber das hört sich für mich wirklich schlecht an. Was ist, wenn das Makro Hilfselemente generieren möchte, auf die nur das Makro zugreifen kann?

Anstatt Hygiene zu verwerfen, ist es meiner Meinung nach besser, eine vollständige Hygiene zu erzwingen, aber Makros die Möglichkeit zu geben, die Hygiene für eine bestimmte Variable explizit abzulehnen.

@joshtriplett Sie würden die Display-Impl für Literal verwenden.

@joshtriplett ja wie @dtolnay erwähnte, würden Sie Display , worauf eine Kiste wie literalext aufgebaut ist. Im Allgemeinen soll die API das "Nur das Nötigste sein", keine erstklassige API, die alle Schnickschnack hat. Die kommen wahrscheinlich später!

Diese Stabilisierungsrunde soll "maximal minimal" sein, in dem Sinne, dass sie die geringste Funktionalität bietet, um alle Anwendungsfälle abzudecken (auch bekannt als Display für Literal und nichts anderes, um es zu interpretieren ).

@Pauan es ist nicht großartig, ja, aber es ist genau dasselbe wie macro_rules! das seit Jahren stabil ist und in vielen verschiedenen Kontexten funktioniert. Wir wollen hier Hygiene und eine bessere Behandlung ermöglichen, sind aber noch nicht ganz fertig. Der Span::call_site() Konstruktor ist hier der Dreh- und Angelpunkt, womit Sie "keine Hygiene" anfordern. Irgendwann werden wir weitere Optionen stabilisieren.

Leider ist "volle 100%ige Hygiene" noch Jahre entfernt, und der Zweck dieses Vorschlags ist es, etwas Stabiles für Rust 2018 zu erreichen

@alexcrichton Ist also der Plan, es jetzt mit einem Hygieneloch zu reparieren?

Da Span::call_site() existiert, gibt es einen Grund dafür, dass es derzeit keine vollständige Hygiene bieten kann? Fehlt es an Manpower/Zeit oder gibt es theoretische/semantische Bedenken, die in einem RFC noch konkretisiert werden müssen?

@Pauan, um es noch einmal zu wiederholen, es gibt kein wirkliches "Loch" in dem Sinne, dass es heute bereits existiert. Dies ist genau die gleiche Hygienegeschichte mit macro_rules! und benutzerdefinierter Ableitung. Dieser Vorschlag ist praktisch eine Erweiterung davon und führt nichts Neues ein.

Angesichts einer "perfekten Hygienegeschichte" werden wir immer eine Form der Abmeldung wünschen. Derzeit beträgt diese Abmeldung Span::call_site() (effektiv). Indem wir nur das stabilisieren, stabilisieren wir nur einen Opt-out-Mechanismus für Hygiene. Schließlich werden wir mehr Funktionalität stabilisieren, um die Artikel bei Bedarf vollständig hygienisch zu machen.

Die Stabilisierung der Hygiene ist viel weiter weg. Es gibt (AFAIK) ungelöste Forschungsfragen, es ist keine Frage der Manpower.

@dtolnay Ah, ich

cc @rust-lang/compiler, ihr alle, die ich kenne, interessiert sich auch sehr dafür und könnt gerne Einwände vorbringen. Wenn Sie einen Sperrwiderspruch haben, kann ich diesen auch für Sie registrieren

Ich habe noch ein paar Dinge zu überprüfen und eine PR mit ein paar Proc-Makro-API-Optimierungen im Gange.

Dies ist genau die gleiche Hygienegeschichte mit macro_rules! und benutzerdefinierte abgeleitet.

Sicher, aber ich dachte, eines der Ziele sei es, ein besseres Makrosystem zu entwickeln, daher klingt es für mich nicht sehr überzeugend, auf das vorhandene (kaputte und begrenzte) System zu verweisen.

Angesichts einer "perfekten Hygienegeschichte" werden wir immer eine Form der Abmeldung wünschen.

Absolut, aber mein Punkt ist , dass , da es möglich ist , zu verwenden Span::call_site() Hygiene brechen (und damit die Gewinn macro_rules! Funktionalität) , falls gewünscht, durch sie hygienisch standardmäßig Sie Zugang zu beiden Hygiene gewinnen und Nicht-Hygiene. Wenn es sich jedoch mit Nicht-Hygiene stabilisiert, bleibt es nur mit Nicht-Hygiene hängen.

Schließlich werden wir mehr Funktionalität stabilisieren, um die Artikel bei Bedarf vollständig hygienisch zu machen.

Das klingt nach einem ziemlich nervigen (und verwirrenden) Pflaster: Proc-Makros wären in den meisten Situationen hygienisch (aber nicht für Gegenstände), aber Sie können dann eine neue Funktion verwenden, um die Hygiene für Gegenstände zu aktivieren. Verstehe ich das richtig?

Es gibt (AFAIK) ungelöste Forschungsfragen, es ist keine Frage der Manpower.

Okay, das ist fair genug. Ich verstehe den Wunsch nach Zweckmäßigkeit und Pragmatismus. Solange der Plan ist, irgendwann in einer späteren Epoche/Ära/Ausgabe standardmäßig eine solide Hygiene zu haben, bin ich damit einverstanden, vorübergehend schlechte Hygiene zu haben. Ich möchte nur nicht, dass wir etwas stabilisieren, was wir später bereuen werden.

In gewissem Sinne ist es bereits „Hygienic Vorgabe : “ Es ist nur , dass der Standard noch nicht unterstützt wird. Span::call_site ist die Abmeldung. :)

@Pauan Um zu erläutern, was @alexcrichton gesagt hat:

Zum Erstellen eines Bezeichners ist ein Span erforderlich, das Hygieneinformationen enthält. (Siehe Term::new )

In Zukunft werden wir möglicherweise viele verschiedene Möglichkeiten zur Konstruktion von Span s aufdecken, die verschiedene Optionen für die Hygiene widerspiegeln. Aber im Moment werden wir nur Span::call_site was den Bereich des Aufrufers einnimmt.

Auf diese Weise können wir vermeiden, das gesamte Hygienesystem sofort zu stabilisieren, während wir uns die Möglichkeit offen halten, später Hygiene hinzuzufügen. Ich denke, es ist ein ziemlich cleverer Trick, um das Problem zu umgehen!

@rpjohnst Sie meinen also, dass die einzige Möglichkeit, neue Elemente aus einem proc-Makro zurückzugeben, darin besteht, Span::call_site ?

Wenn ja, dann klingt das perfekt: Dann kann Hygiene in Zukunft tatsächlich sauber und abwärtskompatibel hinzugefügt werden.

@lfairy Ahhh, ich sehe, ich hatte nicht erkannt, dass es notwendig ist , Span::call_site , ich dachte, es gäbe einen impliziten unhygienischen Standardbereich. Vielen Dank für die Erklärung! Du hast recht, das ist ein sehr cleverer Trick.

Insofern habe ich keine Einwände mehr.

@alexcrichton

Attribute, macro_rules und prozedurale
Makros befinden sich alle im Maro-Namespace.

Zuletzt habe ich mit #[feature(proc_macro)] nachgesehen, es hatte eine abwärtsinkompatible Änderung im stabilen Code für die Ableitungsfehler-Kette, wie hier beschrieben

@Arnavion oh je, das hört sich schlecht an! Wir können keine großen abwärtskompatiblen Änderungen vornehmen, also müssen wir einen Weg finden, damit das funktioniert. Eine mögliche Lösung wäre, "Dies ist kein Attribut"-Fehler bis nach der #[derive] Erweiterung aufzuschieben.

Es scheint, dass #48644 und #47786 fertig sind. Könnte jemand das OP aktualisieren?

@alexcrichton Gab es Diskussionen über den Zugriff auf die internen Daten von Literal und Freunden? Ich verstehe, dass sie aus Gründen der Abwärtskompatibilität keine Enumerationen mehr sind, aber gibt es einen Grund, warum wir so etwas nicht für Literal , um damit zu beginnen:

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

Wir könnten sogar eine Reihe von TryFrom Impls für die verschiedenen Literal-Subtypen haben.

@abonander es wurde ja besprochen, aber die Schlussfolgerung war, sie später hinzuzufügen, anstatt sie für den ersten Stabilisierungsdurchgang erforderlich zu machen. Sie können auf crates.io mit der Display Implementierung erstellt werden und wir haben Platz, um die später in der Zukunft hinzuzufügen

:bell: Dies geht jetzt in seine letzte Kommentarperiode , wie in der obigen Überprüfung beschrieben . :Klingel:

@alexcrichton
!Send und !Sync Impls für proc-Makro-API-Typen werden nicht explizit geschrieben, sondern abgeleitet.
Für einige Strukturen (zB Op ) weicht die abgeleitete Impl von den Angaben in https://github.com/rust-lang/rust/issues/38356#issuecomment -383693017 ab.
Es ist wahrscheinlich sinnvoll, die Impls explizit hinzuzufügen.

Ups ja in der Tat! Ich habe https://github.com/rust-lang/rust/pull/50453 geöffnet, um das zu beheben

@alexcrichton Wir haben ein Term::as_str : Ich habe versucht, einen informellen Beweis dafür zu skizzieren, dass &'a Term -> &'a str aufgrund des strikten Scopings implementiert werden kann, um es an einen Scoped-Interner auszuleihen, und 'a kann niemals größer sein als der Gültigkeitsbereich des Interners selbst (was nur wichtig ist, wenn die Funktion erfolgreich ist, dh wenn sie innerhalb des Gültigkeitsbereichs aufgerufen wird, in dem der Interner aktiv ist).

AFAICT, Term::as_str ist solide , aber nur unter der Annahme, dass 'a Bedingung ist.

Was zB von thread_local! aufrechterhalten wird, denn während Sie damit den Term umgehen können, erhalten Sie sehr kurzlebige 'a s, was, wenn Term::as_str erfolgreich ist, sind strikt kürzer als der interne Gültigkeitsbereich.
Im Allgemeinen geschieht die Erweiterung von proc_macro und da Term thread-lokal ist, gibt es nur sehr wenige Möglichkeiten, Term entkommen, und ich nahm an, dass thread_local! war praktisch der einzige.

Aber Box::leak existiert auch! Es ist immer noch instabil, aber heute gibt Box::leak(Box::new(term)).as_str() &'static str . Ich frage mich, ob es andere Abstraktionen gibt, die von Box::leak (cc @RalfJung) unterbrochen werden.

OTOH, das ist nur kompliziert, weil Term die String-Daten nicht besitzen kann, da es Copy .
Wenn wir Copy auf Term entfernen, könnten wir ein faules Option<Cell<Rc<String>> darin behalten.

@eddyb oh Term::as_str soll entfernt werden und wurde hier nicht in die Stabilisierung einbezogen, also kein Grund zur Sorge! Es bleibt nur so, dass wir proc-macro2 nicht kaputt machen, aber sobald sich das stabilisiert hat, können wir ein Breaking Change für proc-macro2

@eddyb Ich kenne den Kontext hier nicht, aber Box::leak ist in meinem formalen Modell gerechtfertigt. Wenn Sie einen Speicher für immer besitzen (dh in einer Kiste), können Sie absolut sagen, dass er eine Lebensdauer hat.

Ich habe ein paar Fragen:

  1. Wird quote! nicht stabilisiert?
  2. Wird auf quote! das proc_macro_non_items Feature Gate angewendet? Commit 79630d4fdfc775b241cae0a209edec2687a29f0f erfordert es jetzt, aber quote! ist immer noch als #[unstable(feature = "proc_macro" ... markiert.
  3. Werden Tracking-Probleme zur Stabilisierung von proc_macro_path_invoc , proc_macro_mod , proc_macro_expr und proc_macro_non_items eingereicht?

Unabhängige Nebenfrage: Wo ist quote! implementiert? es ist ein verfahren Makro (siehe proc_macro_non_items ), ist hier .

@mjbshaw Sooo lustige Geschichte: Sie ist in proc_macro::quote implementiert.
rustc_metadata gibt vor, dass jede Kiste namens proc_macro ein prozedurales Makro namens quote , aber die verwendete Implementierung stammt aus der proc_macro rustc_metadata Links dagegen.

Ich habe noch ein paar Dinge zu überprüfen und eine PR mit ein paar Proc-Makro-API-Optimierungen im Gange.

Rezensions-PR: https://github.com/rust-lang/rust/pull/50473

Funktionsanfrage für die 1.2 API: Fügen Sie ein Trennzeichen für spitze Klammern hinzu ( < / > ), damit Dinge wie <T> (in fn foo<T>() {} ) als geparst werden ein Group . Wenn Sie dies nicht tun, wird das Parsen zB von Generika unnötig kompliziert.

@mjbshaw Ich glaube nicht, dass es auf Token-Ebene funktionieren würde, um festzustellen, ob zwei < > miteinander gruppiert sind. Zum Beispiel in der folgenden Makroeingabe:

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

Vielleicht sind dies zwei boolesche Ausdrücke $A < $B und $C >= $D , oder vielleicht stellt es Generics in einem Typalias dar, zum Beispiel die Erweiterung auf type $A <$B,$C> = $D; .

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

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

Ich habe das OP leicht aktualisiert, aber wir haben, was für mich wie zwei mögliche Showstopper-Bugs im Zusammenhang mit Hygiene aussieht, je nachdem, wie sie ausfallen:

Für diejenigen, die diesem Thread folgen, wird die API wahrscheinlich vom ursprünglichen FCP-Kommentar in https://github.com/rust-lang/rust/pull/50473, vorgeschlagen von @petrochenkov, geändert. Die Zusammenfassung lautet bisher:

  • Benennen Sie Term::new in Term::ident und bestätigen Sie die Eingabe
  • Fügen Sie Term::lifetime und bestätigen Sie die Eingabe
  • Term::raw_ident hinzufügen und Eingabe bestätigen
  • Benennen Sie Op in Punct
  • Überprüfen Sie die Eingabe auf Punct::new
  • Benennen Sie Op::op in Punct::as_char

Eine kleine API-Anfrage, die ich stellen würde (möglicherweise in #50473 -- @petrochenkov) ist eine Möglichkeit, Token an einen TokenStream anzuhängen. Möglicherweise:

impl Extend<TokenTree> for TokenStream

Ich glaube, dies würde es ermöglichen, den Typ quote::Tokens (der im Grunde Vec<TokenTree> ) zu eliminieren und die Verbreitung verschiedener Typen im Ökosystem zu reduzieren, die alle "einige Token" bedeuten - verfolgt in https ://github.com/dtolnay/syn/issues/205.

+1 zu dem obigen Vorschlag von @dtolnay.

Die letzte Kommentierungsfrist mit der Möglichkeit zur Fusion gemäß der obigen Überprüfung ist nun abgeschlossen .

Ich habe zwei Fragen:

  1. Wie schon hier gefragt, was ist mit quote! ? Was sollte die Standardmethode sein, um das endgültige TokenStream zu erstellen? Sollte es manuell erfolgen? Oder sollte man die quote Kiste verwenden? Soll proc_macro::quote! irgendwann in der Zukunft stabilisiert werden?

  2. Ist mein Verständnis insofern richtig, als der Unterschied zwischen der Deklaration eines funktionsähnlichen Makros und eines attributähnlichen Makros nur die Anzahl der Argumente ist? Dh:

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

    Der einzige Unterschied besteht darin, dass man eins TokenStream als Argument nimmt, während das andere zwei nimmt. Ist das nicht ein bisschen subtil? Warum nicht stattdessen #[proc_macro_attribute] und #[proc_macro_function_like] verwenden? Wurde das schon irgendwo diskutiert? Wenn ja, würde ich mich freuen, wenn jemand die Diskussion verlinken könnte.

Danke für deine Arbeit dazu! :)

@LukasKalbertodt Attribute werden derzeit mit #[proc_macro_attribute] deklariert. Ich weiß nicht, ob dies absichtlich geändert werden soll oder ob es sich um einen Tippfehler im FCP-Vorschlag handelt.

Problem: Aus Strings geparste Token erhalten keine Span::call_site Spans: https://github.com/rust-lang/rust/issues/50050#issuecomment -390520317.

Ich denke, wir müssen dies ändern und auch ändern, was Span::call_site zurückgibt, um Makro-Backtraces, Clippy und Editionshygiene für Token mit Call-Site-Spans zu korrigieren.

@LukasKalbertodt das quote! Makro in der proc_macro Kiste wird im Rahmen dieses FCP nicht stabilisiert, aber die quote Kiste auf crates.io baut auf der hier vorgeschlagenen API auf. Auch wie @abonander betonte, werden Attributmakros mit #[proc_macro_attribute] deklariert und #[proc_macro] ist ausschließlich für foo!() -Makros reserviert

Sollte #[proc_macro_attribute] nicht #[proc_attribute_macro] oder #[attribute_proc_macro] heißen?

@Zoxc Wir haben bereits #[proc_macro_derive] stable, daher wäre es seltsam, dies für Attributmakros nicht zu befolgen.

Können wir PartialEq<char> und PartialEq<Punct> für Punct (ähnlich den PartialEq Implementierungen von Ident )? Es scheint, als ob das Hinzufügen ziemlich sicher sein sollte. Gerne schreibe ich die PR, möchte aber nicht, wenn die Idee ein No-Go ist.

@mjbshaw Würde PartialEq<Punct> auch Spannen vergleichen? PartialEq<char> scheint in Ordnung zu sein, OTOH.

@eddyb PartialEq für Ident vergleicht keine Spans (ich weiß, dass dies proc-macro2-Quelle und nicht proc-macro-Quelle ist). Ich bin ambivalent, ob Spans in den Vergleich einbezogen werden, aber ich würde erwarten, dass sich Punct und Ident in dieser Hinsicht ähnlich verhalten. Punct hat auch ein eigenes Spacing , von dem ich annehme, dass es in den Vergleich einbezogen wird (obwohl andere vielleicht anders denken).

Mir wäre es gut, vorerst nur PartialEq<char> für Punct zu implementieren. PartialEq<Punct> können später gehasht werden.

@mjbshaw die proc-macro2-Kiste hat die Freiheit, nicht genau das zu sein proc_macro im Upstream ist, und gibt uns die Freiheit, mit verschiedenen Optimierungen zu experimentieren. Ich vermute, dass, wenn es auf crates.io gut funktioniert, wir es zu proc_macro hinzufügen können, aber es ist natürlich abwärtskompatibel, um es zu proc_macro hinzuzufügen, also beginnen wir mit dem Nötigsten und Wir können von dort aus hochskalieren, sobald es stabil ist.

Ich habe einige Triage-Arbeiten für alle Fehler im Zusammenhang mit Makros 1.2 durchgeführt . Die meisten Bugs können in "serious bugs" oder "alle span-related bugs" eingeteilt werden. Derzeit betreffen Span-bezogene Fehler nur Fehlermeldungen (da die Absicht von Makros 1.2 nicht darin besteht, die Auflösung zu ändern). Der verbleibende nicht-span-bezogene Fehler (auch bekannt als schwerwiegend) ist https://github.com/rust-lang/rust/issues/50050 , für den @petrochenkov eine Lösung hat .

Die Gnome-Klasse brach mit den Änderungen an proc_macro2/syn/quote sowie dem Feature-Gate zum Generieren von Modulen aus proc-Makros. Jetzt ist es zum Glück behoben.

Welche Dinge sollte ich überwachen, um die Veränderungen in diesem kleinen Ökosystem im Auge zu behalten?

@federicomenaquintero Wenn Sie instabile Funktionen verwenden, sollten Sie einen regelmäßigen CI-Job (täglich, wöchentlich, was immer für Sie funktioniert) in Betracht ziehen, der Ihren Code mit dem neuesten Nightly kompiliert und Sie benachrichtigt, wenn er fehlschlägt. (Travis-CI unterstützt die Aktivierung eines solchen "Cronjobs" in seinen Einstellungen.)

@SimonSapin danke, das ist eine gute Idee. Wir heften Versionen dieser Kisten in unser Cargo.toml, aber es kann an der Zeit sein, die Versionsnummern zu entfernen und Cargo einfach die neuesten herunterladen zu lassen. Ist das der richtige Weg?

@federicomenaquintero Dies wird zunehmend vom Thema also , wenn Sie diese Diskussion fortsetzen möchten , wenden Sie sich bitte so irgendwo anderes tun , wie im IRC oder http://users.rust-lang.org/ , aber die allgemeine Empfehlung ist , dass Anwendungen (wie im Gegensatz zu Bibliotheken) sollten Cargo.lock zusammen mit ihrem Quellcode liefern, was effektiv Abhängigkeiten festlegt. In Cargo.toml wird empfohlen, eine Abhängigkeit wie foo = "1.2.3" deklarieren, es bedeutet implizit "diese Version oder höher, wenn gemäß SemVer kompatibel".

Also, ich bin gerade auf ein Problem mit prozeduralen Makros gestoßen, das mich daran hindert, eine Kiste zu entwickeln, die ich herstellen möchte.

Folgendes berücksichtigen:

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

Dies funktioniert derzeit nicht, da die beiden Funktionen proc_macro und custom_attributes erforderlich sind, aber nicht gleichzeitig verwendet werden können. Wie ich verstehe, würde die Stabilisierung von Proc-Makros die Notwendigkeit für die Feature-Flags beseitigen?

Die andere Sache ist, dass #[my_attribute] diese Weise möglicherweise Code generieren könnte, der verhindert, dass #[other_attribute] jemals ausgeführt wird. Was wäre wirklich cool, wenn ich für das "äußere" Attribut innere Attribute registrieren könnte, die genauso funktionieren wie #[derive(Foo)] .

Was ist mit @SimonSapins Kommentar zur Dummy-Sitzung ?

Wäre es möglich/wünschenswert, diese Panik durch das implizite Erstellen einer Dummy-"Sitzung" zu ersetzen? Oder fügen Sie vielleicht eine öffentliche API (mit einem Pfad zur Stabilisierung) hinzu, um eine zu erstellen?

Ich denke, es wäre sehr nützlich, eine Dummy-Sitzung zu haben. Das Schreiben von Unit-Tests für proc-macro Kisten ist ansonsten so gut wie unmöglich oder zumindest sehr umständlich. Darüber hinaus sind es nicht nur TokenStream::from_str , sondern auch andere Funktionen, die eine Sitzung erfordern.

@alexcrichton

Ich habe einige Triage-Arbeiten für alle Fehler im Zusammenhang mit Makros 1.2 durchgeführt. Die meisten Bugs können in "serious bugs" oder "alle span-related bugs" eingeteilt werden.

Ich möchte https://github.com/rust-lang/rust/issues/50504 auf den Status "ernst" aktualisieren - das dort beschriebene Modulproblem ist nur ein Symptom für ein tieferes Problem - Erweiterungs-IDs für proc-Makros nicht richtig registriert werden. Ich weiß nicht, welche anderen Konsequenzen das haben kann.
Es gibt eine PR, die das zugrunde liegende Problem behebt (https://github.com/rust-lang/rust/pull/51952), aber es gibt Rückschritte aus dem Fix und ich habe sie noch nicht durchgesehen.

Ich habe eine PR zur Stabilisierung weiterer prozeduraler Makros unter https://github.com/rust-lang/rust/pull/52081 . gepostet

@petrochenkov hört sich gut an, ich werde die PR kommentieren

Ich habe gerade zum Thema Makronamensverfolgung über Probleme mit untergeordneten proc_macro_derive Attributen und deren Interaktion mit dem Benennungssystem gepostet. Es gibt noch ein weiteres Problem mit der Art und Weise, wie proc_macro_derive Attribute mit dem Bereich und der Benennung interagieren, aber es scheint hier relevanter zu sein. Da Pfade in Attributen derzeit nicht auf Stabilisierungskurs sind, besteht die Möglichkeit, dass #[derive(foo::Parent)] ein untergeordnetes Attribut #[foo::Child] , aber das Ableitungsmakro hätte auf den ersten Blick keine Möglichkeit, dies zu tun Identifizieren Sie, ob das untergeordnete Attribut tatsächlich ein eigenes untergeordnetes Element ist, da es keine Namenssuche durchführen kann. Im Moment habe ich keine einfache Lösung, aber ich denke, dass es etwas ist, das für die Zukunft der voneinander abhängigen Attribute auf dem Radar sein sollte; Es gibt keinen Grund, warum proc_macro_attribute Attribute nicht auf eine Weise interagieren möchten, die zu ähnlichen Suchproblemen führt.

Ich habe heute versucht, mein Projekt zu kompilieren, aber etwas ist defekt, was wahrscheinlich mit diesem Problem zusammenhängt. Alle Fehlermeldungen hatten die Meldung: "(siehe Issue #38356)". So bin ich hierher gekommen.
Ich füge hier die Fehlermeldung ein, die ich während der Kompilierung erhalten habe. Ich füge auch mein Cargo.toml ein.

Das finde ich sehr überraschend, da mein Projekt an eine bestimmte Rust-Nightly-Version gepinnt ist (rustc 1.29.0-nightly (9bd8458c9 2018-07-09)) Was könnte sich geändert haben? Möglicherweise eine Bibliothek aktualisiert?

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

Kompilierungsfehler

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

Haben Sie eine Idee, was schief gelaufen sein könnte und wie es behoben werden kann? Vielen Dank!

@realcr für die proc-macro2 Kiste kannst du einfach cargo update ausführen und das sollte den Zweck erfüllen !

@alexcrichton Ich glaube nicht, dass das hier das Problem ist. Ich denke eher, @realcr hat proc-macro2 bereits aktualisiert, da die Fehlermeldung überall proc-macro2-0.4.8 sagt. Das Problem ist eher, dass die nächtliche Version auf eine gefixt wurde, die #52081 nicht enthält. Ich hatte heute das gleiche Problem und habe mich gefragt, warum proc-macro2 nur die Nebenversion geändert hat. Aber ich bin nicht sehr vertraut damit, wie proc-macro2 mit der Kompatibilität umgeht.

@realcr Versuchen Sie, Ihren nächtlichen Compiler zu aktualisieren, oder erzwingen Sie eine proc-macro-2 Version < 0.4.8 in Ihrem Projekt.

@alexcrichton , @LukasKalbertodt : Danke für die schnelle Antwort.
Ich habe gerade meinen Nightly Compiler auf die neueste Version aktualisiert. Es beseitigte zwar die proc-macro-2-Probleme, aber ich bekam viele neue Kompilierungsfehler. Beispiel:

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)

Zur Bestätigung meine aktuelle Version von rustc:

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

Um die Ursache des Problems aufzuspüren, habe ich versucht, das grundlegende Beispiel aus

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

Weil Sie die instabile Funktion verwenden.

@realcr Ihr neues Kompilierungsproblem hat nichts mit diesem Problem zu

@TeXitoi : Fühlen Sie sich frei, alles zu bearbeiten oder zu entfernen, wenn Sie der Meinung sind, dass es nicht relevant ist. Ich versuche mein Bestes, um Ihnen zu helfen, es ist schwierig für mich zu wissen, was zum Thema ist und was nicht. Die Fehlermeldung "(siehe Issue #38356)" hat mich hierher geführt.

Ich habe versucht, meine Compiler-Version zu aktualisieren, und ich habe diesen Fehler. Mein Code

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

#[macro_use(eth_abi)]
extern crate pwasm_abi_derive;

und Fehler, der besagt, dass ich #![feature(proc_macro)] , aber ich habe es getan!

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 du #![feature(proc_macro)] auf #![feature(use_extern_macros)] umstellen und das sollte den Zweck erfüllen

Ich denke, Sie müssen das Modulsystem auch verwenden, um prozedurale Makros zu importieren (und sicherstellen, dass Sie einen aktuellen nächtlichen Compiler haben).

@alexcrichton ja, dank des Artikels habe ich es gerade herausgefunden. Es funktioniert jedoch immer noch nicht:

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

Importregeln für Makros haben sich auch geändert? Oder ich kann nicht herausfinden, warum es hier angefangen hat, sich zu beschweren.

@Pzixel , das kann ein Fehler im prozeduralen Makro oder im Compiler sein, können Sie dafür ein spezielles Problem einreichen?

Nun, ich denke, ich sollte meinen Code zuerst umschreiben, damit er zumindest funktioniert :) Im Moment tut es das nicht, ihr habt euch mit dieser Funktion sehr verändert. BRB wenn fertig. Wenn es nicht verschwindet, erstelle ich ein Problem.

@alexcrichton
Wissen Sie, welche "Vorverarbeitung" auf Token angewendet wird, bevor sie an ein prozedurales Makro übergeben werden?
Ich weiß, dass Ableitungen mindestens $crate eliminiert und cfg erweitert wurden, bevor sie Eingabetoken erhalten (plus Roundtrips durch Strings sind nicht ganz verlustfrei, aber das ist korrigierbar).

Wir sollten sicherstellen, dass dies bei neu stabilisierten prozeduralen Makros nicht passiert und sie Eingabetoken präzise erhalten (Modulo-Bugs).

@alexcrichton Entschuldigung, cargo expand funktioniert aus irgendeinem Grund nicht mit dieser Kiste. Kann nicht bestätigen, ob das Problem auf meiner Seite oder auf einem Compiler liegt. Also mache ich mir weiterhin die Schuld, bis diese Möglichkeit nicht vollständig ausgeschlossen ist.

@petrochenkov Die Erweiterung von Proc-Makros wurde bisher ziemlich gut überprüft, daher mache ich mir viel weniger Sorgen als die Namensauflösungsstücke. Ich kenne die Vorverarbeitung nicht persönlich, aber ich weiß, dass es eine Erweiterungsreihenfolge gibt, bei der Ableitungen zuletzt ausgeführt werden, cfgs zuerst ausgeführt wird und ansonsten hauptsächlich iterativ ist.

Ich stimme jedoch zu, dass es gut ist, dafür zu auditieren!

Vielleicht habe ich etwas Offensichtliches übersehen. Aber gibt es keine Möglichkeit, eine Funktion aufzurufen, einen Typ zu verwenden usw. aus der proc_macro-definierenden Kiste aus einer prozeduralen Makroerweiterung? (oder jede andere Kiste, die aus der proc_macro-Kiste, FWIW bekannt ist)

Es gibt Problemumgehungen, aber AFAIU sie funktionieren nicht, wenn die Kiste vom Benutzer des prozeduralen Makros umbenannt wird.

@Ekleog proc-Makro Kisten werden in der Regel nur für die Zwecke des Aufbaus Kisten zusammengestellt , die sie verwenden. Sie sind keine Laufzeitabhängigkeiten. Sie können sich die gesamte Proc-Macro-Kiste als eine Art Compiler-Plugin vorstellen, nicht als "normale" Bibliothek.

Dies ist besonders beim Cross-Compiling sichtbar: Proc-Makros werden wie Build-Skripte für die Host-Plattform kompiliert, nicht für die Zielplattform.

@SimonSapin Ich stimme dir zu, aber es kann wirklich nützlich sein, einen Teil der Arbeit an eine Funktion zu delegieren, die von einer X-derive Kiste versucht, eine Funktion aus der X Kiste zu verwenden). Denn ansonsten würde das bedeuten, dass der gesamte von proc-Makros generierte Code entweder in sich geschlossen sein oder Annahmen über den Zustand der Anrufseite treffen muss.

Dann kann ich verstehen, dass rustc noch nicht für diese Art von Funktion bereit ist (weil ich denke, es würde am besten funktionieren, ohne dass Proc-Makros von Nicht-Proc-Makro-Kisten getrennt werden müssen, was irgendwo auf der langen Seite zu sein scheint. Begriff Roadmap). Aber ich frage mich, ob es möglich sein wird, diese Funktion später nachzurüsten, wenn die aktuelle Schnittstelle, die nur TokenStreams stabilisiert wird? Braucht es nicht so etwas wie einen Token-Typ PathToBeResolvedFromTopOfGeneratingProcMacroCrate ? (was eine bahnbrechende Änderung wäre, wenn sie später hinzugefügt würde, afaiu)

Vielleicht wird es irgendwann möglich sein, die Dinge flexibler zu gestalten, aber das scheint ziemlich weit weg zu sein.

Wenn Sie Bibliotheksautor sind, sollten Sie in der Zwischenzeit eine foo-proc-macros oder foo-derive Kiste für prozedurale Makros und eine "normale" foo Bibliothek mit Laufzeiten in Betracht ziehen Code, sondern reexportiert auch die prozeduralen Makros. Auf diese Weise kann die benutzerorientierte API in einer einzigen Kiste gehalten werden. Das macht serde (in einigen Konfigurationen) https://github.com/serde-rs/serde/blob/v1.0.71/serde/src/lib.rs#L304

Es ist jedoch erwähnenswert, dass diese Problemumgehung immer noch nicht das Problem behebt, dass der Benutzer die Root- zB das Tracking-Problem von Serde ).

@Ekleog , TokenStream ist ein Stream von TokenTree s und jedem TokenTree sind Span , die die Bereichsinformationen enthalten. Außer, dass es derzeit keine Möglichkeit gibt, einen Span für einen anderen Bereich als „Call Site“ (oder leer) zu erstellen. Im Grunde ist es erforderlich, eine einigermaßen ergonomische Methode zu finden, um Span s zu erstellen, die sich auf eine bestimmte Kiste beziehen.

Der Grund, warum ich gefragt habe, ist, dass das Kontrollkästchen nicht aktiviert ist. Wäre schön, wenn du es dann ankreuzen würdest!

Nachdem sich #![feature(proc_macro)] stabilisiert hat, was bleibt von diesem Problem übrig?

@jan-hudec Oh, ich dachte, Span s dienen nur der Fehlerberichterstattung, da in frühen Blog-Posts eine Hygiene -Struktur (oder ähnlich genannt) erwähnt wurde, die diese Rolle spielte. Ich hatte angenommen, dass diese verschwunden waren, und lag anscheinend falsch. Vielen Dank! :)

Wenn #![feature(proc_macro)] stabilisiert ist, was bleibt von diesem Problem übrig?

Idealerweise müssen für alle einzelnen verbleibenden Probleme und nicht stabilisierte Funktionen neue Probleme eingereicht werden, und dann kann dieses Problem geschlossen werden (genau wie bei https://github.com/rust-lang/rust/issues/). 44660).

Oh, ich dachte, Spans dienen nur der Fehlerberichterstattung, da in frühen Blog-Posts eine Hygiene-Struktur (oder ähnlich genannt) erwähnt wurde, die diese Rolle spielte. Ich hatte angenommen, dass diese verschwunden waren, und lag anscheinend falsch. Vielen Dank! :)

IIUC, Spans sind der wichtigste Weg, um den Hygienekontext zu verfolgen.

@mark-im Irgendwie. Sie umfassen sowohl Informationen zum Standort des Quellcodes (für benutzerorientierte Nachrichten/Diagnose) als auch den Syntaxkontext (dh Hygieneinformationen).

Ist es angesichts der Menge an Diskussionen/Traffic, die dieses Problem erhält, sinnvoll, proc_macro_diagnostic in ein eigenes Tracking-Problem zu verschieben? Ich würde auch gerne herausfinden, was die Blocker für die Stabilisierung dieser Funktion sind, und sehen, ob wir sie durchsetzen können. Diesel verwendet es, und es war bisher großartig. Das Fehlen dieser Funktion bei Stable führt dazu, dass die Community funky Workarounds erstellt, wie die neueste Version von syn, die stattdessen compile_error! .

@sgrif Ich habe ein solches Problem geöffnet: https://github.com/rust-lang/rust/issues/54140.

Daher bin ich daran interessiert, die Methoden in Span und der LineColumn-Struktur zu stabilisieren. Ich werde mir die offenen Probleme im ersten Kommentar ansehen, aber wenn jemand einen Neuling auf den Compiler in eine bestimmte Richtung weisen möchte, würde ich mich freuen :+1:

Das Feature-Gate proc_macro_gen mich hierher geführt, aber in der Checkliste oben sehe ich nichts, was offensichtlich auf ein (proc_)Makro verweist, das andere Makrodefinitionen generiert. Wurde dies berücksichtigt (außer im Feature-Gate von rustc)?

@jjpe es ist ausgliedern. Dieses Problem war größtenteils der ersten Welle der Stabilisierungen gewidmet

@alexcrichton Mir geht es vollkommen gut, es ist eher so, dass ich beim Betrachten der proc_macro_gen Funktion hierher verwiesen wurde, nur um so gut wie keine Erwähnung davon zu finden. Das ist mir ein bisschen seltsam, also habe ich beschlossen, es zumindest zu erwähnen.

@xieyuheng Wie würde CodeString / Code überhaupt aussehen, dh wie wäre ihre Semantik?
Denken Sie daran, dass TokenStream nichts anderes als der wörtliche Quellcode ist, außer als eine Reihe von Token-Werten und nicht als lästiger Text.

Die erweiterte API für TokenStream (mit TokenTree ) ist in 1.29 stabil. Das Importieren von funktionsähnlichen Proc-Makros wird in 1.30 stabil sein.

Es scheint, dass es seit rustc 1.30.0-nightly (63d51e89a 2018-09-28) nicht mehr möglich ist, Code innerhalb eines Moduls in einer separaten Datei zu durchlaufen. Wenn Sie mod module; , erhalten Sie TokenStream mit mod module; , WYSIWYG.

Ich verstehe, dass dies notwendig ist, um Spannweiten, Hygiene und Konsistenz mit dem verarbeiteten Code zu erhalten. Gibt oder wird es eine Möglichkeit geben, mit Inhalten von Modulen in separaten Dateien zu arbeiten? Sein Fehlen kann für Endbenutzer verwirrend sein, wenn eine triviale Umgestaltung der Modulorganisation zu einer Änderung des Makroverhaltens führt.

Ok, dieses Problem ist massiv und ist so weit gekommen, dass es meiner Meinung nach nicht mehr allzu nützlich ist, weiter offen zu bleiben und APIs zu verfolgen. Zu diesem Zweck habe ich https://github.com/rust-lang/rust/pull/54728 geöffnet, was dieses Problem in eine Reihe feinkörnigerer Tracking-Probleme aufteilt:

An dieser Stelle werde ich dies schließen, aber wenn ich vergessen habe, andere Tracking-Probleme abzutrennen, lass es mich bitte wissen! Ich kann sicherlich noch ein paar Follow-ups eröffnen

@alexcrichton Was ist mit
https://github.com/rust-lang/rust/issues/38356#issuecomment -397095541
Gibt es dafür ein Problem?

@XX
Solche Unterattribute müssen nicht unbedingt ein Sprachmerkmal sein?
Im Fall von derive Registrierung von benutzerdefinierten Attributen erforderlich, da Ableitungsmakros keine Attribute aus ihrer Eingabe entfernen können (die Eingabe ist unveränderlich).
Attributmakros können #[other_attribute] s aus ihrer Eingabe entfernen, sodass sie nie zur Namensauflösung gelangen und niemals den Fehler "unaufgelöstes Attribut" melden.

(Außer den in https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541 erwähnten klassischen Legacy-Instabilen benutzerdefinierten Attributen sind jetzt mit Proc-Makros kompatibel.)

@petrochenkov Ja, danke für die Klarstellung.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen