Rust: Masalah pelacakan untuk RFC 1566: Makro prosedural

Dibuat pada 14 Des 2016  ·  184Komentar  ·  Sumber: rust-lang/rust

Status terkini

Masalah ini telah ditutup demi masalah pelacakan yang lebih halus

~Deskripsi yang Diperbarui ~

Langkah selanjutnya:

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

    • menunggu di kawah

  • [ ] Stabilkan fitur proc_macro

Kemungkinan Stabilisasi Showstoppers

Deskripsi Asli

RFC .

RFC ini mengusulkan evolusi sistem makro prosedural Rust (alias sintaks
ekstensi, alias plugin kompiler). RFC ini menentukan sintaks untuk definisi
makro prosedural, tampilan tingkat tinggi dari implementasinya di kompiler,
dan menguraikan bagaimana mereka berinteraksi dengan proses kompilasi.

Pada level tertinggi, makro didefinisikan dengan mengimplementasikan fungsi yang ditandai dengan
atribut #[macro] . Makro beroperasi pada daftar token yang disediakan oleh
kompiler dan kembalikan daftar token yang digantikan oleh penggunaan makro. Kita
menyediakan fasilitas tingkat rendah untuk beroperasi pada token ini. Tingkat lebih tinggi
fasilitas (misalnya, untuk mengurai token ke AST) harus ada sebagai peti perpustakaan.

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


tugas

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

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

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

  • [x] Terapkan #[proc_macro] (PR #40129).
  • [x] Identifikasi dan kumpulkan penggunaan proc_macro_derive dalam InvocationCollector (PR #39391).
  • [x] Mendukung impor proc_macro_derive diperluas secara makro.

    • Sebagai contoh:

#[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!();
  • [ ] Perluas item sebelum memperluas diterapkan proc_macro_derive s (PR #48465).
  • [x] Terapkan peringatan untuk impor #[macro_use] (PR #39060).
  • [x] Memfaktorkan ulang parser untuk menggunakan pohon token (PR #39118).
  • [x] Bersihkan TokenStream sebagai persiapan untuk pemfaktoran ulang lebih lanjut (PR #39173).
  • [x] Hapus TokenTree::Sequence (PR #39419).
  • [x] Gunakan TokenStream s alih-alih Vec<TokenTree> dalam tokenstream::TokenTree 's Delimited varian (PR #40202).
  • [x] Gunakan Path s dan TokenStream s dalam ast::Attribute s (PR #40346).

    • [x] Mendukung jalur nontrivial dalam makro atribut/turunan (misalnya #[foo::bar] , #[derive(foo::Bar)] ).

  • [x] Sertakan informasi kebersihan dengan semua token, bukan hanya pengenal (PR #40597).
  • [x] Terapkan API minimal untuk proc_macro::TokenStream seperti yang dijelaskan dalam RFC (PR #40939).

    • [x] Sertakan sumber TokenStream s untuk fragmen AST yang diinterpolasi dalam token Token::Interpolated .

    • [x] Sertakan kutipan TokenStream proc_macro::quote! belakang gerbang fitur proc_macro .

  • [x] Menyediakan cara bagi penulis proc_macro untuk membuat perluasan yang menggunakan item dalam peti yang telah ditentukan foo tanpa mengharuskan pengguna makro untuk menyertakan extern crate foo; di akar peti (PR # 40939).

    • [ ] Meningkatkan ergonomi.

  • [ ] Sertakan sumber TokenStream s untuk item dalam AST.
  • [ ] Pemeriksaan stabilitas (proc-)makro (masalah #34079).
  • [x] Izinkan makro proc untuk menginisialisasi bidang pribadi dengan nilai def_site (masalah #47311). (PR #48082)
  • [x] Inkonsistensi antara mengakses bidang struct braced vs struct Tuple di proc makro (masalah #47312). (PR #48083)
  • [ ] Jadikan std tersedia untuk root makro proc di fase 1 (edisi #47314).
  • [x] Memperbaiki kesalahan dari sintaks yang tidak valid di dalam proc_macro::quote! (masalah #47315).
  • [ ] Inkonsistensi antara Display dan IntoIterator untuk TokenStream yang berisi modul (masalah #47627).
  • [x] #[cfg_attr] membuat .to_string() dan TokenStream tidak setuju (masalah #48644).
  • [x] Wishlist untuk libproc_macro (daftar periksa di #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

Komentar yang paling membantu

Oke masalah ini sangat besar dan sampai pada titik yang menurut saya tidak terlalu berguna untuk tetap membuka dan melacak API. Untuk itu saya telah membuka https://github.com/rust-lang/rust/pull/54728 yang membagi masalah ini menjadi beberapa masalah pelacakan yang lebih halus:

Pada titik ini saya akan menutup ini, tetapi jika saya lupa memisahkan masalah pelacakan lainnya, beri tahu saya! Saya pasti bisa membuka beberapa tindak lanjut

Semua 184 komentar

cc @nrc @jseyfried

Saya ingin #[proc_macro_attribute] segera diimplementasikan. Saya sudah memiliki prototipe dan menguji penggunaan yang saya lakukan sebelum menyadari bahwa belum ada dukungan kompiler :unamused: :

Prototipe: https://github.com/abonander/anterofit/blob/proc_macro/macros/src/lib.rs
Contoh/Tes: https://github.com/abonander/anterofit/blob/proc_macro/examples/post_service_proc_macro.rs

tugas

(edit dtolnay: pindahkan daftar periksa ke OP)

cc @nrc @petrochenkov @durka @Ralith

@jseyfried Saya mengalami masalah di mana jika makro warisan dan atribut dengan nama yang sama diimpor ke dalam cakupan yang sama, mencoba menggunakan atribut akan menimbulkan kesalahan bahwa makro tidak dapat digunakan sebagai atribut. Bisakah kita membuat ini bekerja sehingga keduanya dapat berada dalam ruang lingkup yang sama dan dapat digunakan sebagaimana mestinya?

@abonander Semua makro (bang, atribut, dan turunan) berbagi namespace yang sama, jadi kami tidak dapat menggunakan dua makro berbeda dengan nama yang sama dalam lingkup yang sama. Namun, kami dapat memperbaiki pesan kesalahan itu -- dapatkah Anda membuka masalah?

Maaf aku terlambat ke pesta. Saya senang dengan arahan untuk mengekspos token daripada AST, tetapi saya memiliki beberapa kekhawatiran tentang TokenStream API spesifik yang diusulkan di RFC :

pub enum TokenKind {
    Sequence(Delimiter, TokenStream),

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

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

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

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

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

pub enum StringKind {
    Regular,
    Byte,
}

Tidak jelas apakah API ini dimaksudkan sebagai rencana lengkap yang diterima ketika RFC digabung, atau hanya sebuah contoh untuk dikerjakan nanti.

Secara umum, ini tampaknya jauh dari sintaksis Rust "normal" yang diterima oleh kompiler di luar makro. Sementara beberapa makro ingin mengurai beberapa bahasa khusus domain ad-hoc, yang lain ingin mengurai sintaks "Karat sebenarnya" dan memahaminya.

  1. (Kecil) Saya rasa Eof tidak perlu. Iterator mungkin akan digunakan untuk, yah, mengulangi TokenStream dan Iterator::next sudah mengembalikan None untuk menandakan akhir dari iterasi.

  2. (Kecil) Saya rasa Exclamation , Dollar , atau Semicolon tidak diperlukan. Mencocokkan pada Punctuation('!') misalnya tidak lebih sulit.

  3. (Kecil) Seperti yang telah disebutkan orang lain dalam RFC PR, kami mungkin ingin menghilangkan komentar yang bukan komentar dokumen. (Kasus penggunaan apa pun yang ingin mempertahankan komentar kemungkinan juga ingin mempertahankan spasi.)

  4. Sejauh yang saya tahu, apa yang harus dilakukan dengan operator multi-karakter (yang masing-masing mungkin harus berupa satu token) masih merupakan pertanyaan terbuka. Solusi yang mungkin dibahas dalam komentar PR, tetapi sepertinya itu tidak berhasil menjadi teks RFC.

  5. Angka literal tidak ada. Apakah makro seharusnya mengurai [Punct('1'), Punct('_'), Punct('2'), Punct('3'), Punct('4'), Punct('.'), Punct('5'), Punct('e'), Punct('6')] sendiri untuk mengevaluasi literal? Mereka bahkan tidak dapat menggunakan str::parse::<f32> untuk melakukan itu, karena sintaks yang diterimanya tidak sama dengan sintaks literal Rust (yang dapat memiliki _ di tengah, misalnya).

    Saya membayangkan bahwa ada masalah stabilitas di sini. Bisakah kita memperkenalkan tipe numerik baru seperti u128 / i128 (dan mungkin di masa mendatang f128 , u256 , …) dan literalnya, tanpa merusak perubahan pada API token? Salah satu cara untuk memungkinkan hal ini adalah:

    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
    

    Atau mungkin sesuatu yang lain. Tapi saya tidak berpikir "angka pura-pura tidak ada" adalah cara yang baik untuk melakukannya.

  6. // Word didefinisikan oleh Unicode Standard Annex 31 -

    Definisi ini perlu lebih tepat dari itu. UAX 31 menentukan beberapa variasi sintaks pengenal yang berbeda, dan tidak ada satupun yang disebut "word". Tetapi memilih variasi yang tepat yang kami inginkan adalah alasan mengapa pengidentifikasi non-ASCII saat ini dibatasi fitur .

    Sebaliknya, saya pikir ini harus didefinisikan sebagai "apa pun yang diterima oleh kompiler saat ini sebagai pengidentifikasi atau kata kunci" (yang dapat berubah per #28979). Mungkin dengan pub fn is_identifier(&str) -> bool API publik di libmacro.

  7. String Unicode dan literal string byte berbagi varian token tunggal, yang menurut saya salah karena representasi memori dari nilainya memiliki tipe yang berbeda ( str vs [u8] ). Juga tidak jelas apakah komponen text: Symbol dimaksudkan sebagai potongan literal dari kode sumber atau nilai setelah menyelesaikan pelolosan garis miring terbalik. Saya pikir itu pasti yang terakhir. (Sebagai perbandingan, Char(char) harus menjadi yang terakhir karena \u{A0} membutuhkan lebih dari satu char untuk direpresentasikan secara harfiah.)

cara lain untuk menulis makro tingkat tinggi akan menggunakan cadel seperti makro, tetapi ini akan membutuhkan representasi ekspresi-s untuk keseluruhan karat.

@SimonSapin ,

Seperti yang telah disebutkan orang lain dalam RFC PR, kami mungkin ingin menghilangkan komentar yang bukan komentar dokumen. (Kasus penggunaan apa pun yang ingin mempertahankan komentar kemungkinan juga ingin mempertahankan spasi.)

Tolong jangan. Saya memiliki kasus penggunaan di mana saya ingin menggunakan (meskipun tidak mempertahankan—mereka akan ditulis ke dalam produk kompilasi terpisah) komentar dalam sintaks.

Secara khusus, saya ingin membuat makro terjemahan yang akan memuat terjemahan string dari file sumber terpisah dan saya ingin membuat daftar string yang akan diterjemahkan sebagai produk sampingan dalam build debug. Dan perlu ada cara untuk memasukkan komentar yang akan dipancarkan ke dalam daftar itu (rust-locale/rust-locale#19). Jadi masuk akal untuk menggunakan sintaks komentar dan makro perlu melihatnya.

Saya setuju dengan poin lain dalam posting itu.

@jan-hudec
Bahkan jika kami tidak memiliki TokenKind::Comment , Anda masih dapat menggunakan komentar dengan melihat konten rentang di antara token yang berurutan.

Saya tidak berpikir kita seharusnya tidak memiliki TokenKind::Comment untuk mendorong makro prosedural untuk mengabaikan komentar sehingga pengguna bebas menambahkan komentar ke permintaan makro tanpa khawatir tentang mengubah semantik.

@jan-hudec Apakah ada alasan mengapa atribut tidak berfungsi dengan solusi Anda?

@abonander , atribut sama sekali tidak masuk akal. String yang dapat diterjemahkan bertindak sebagai literal, bukan sebagai item. Tetapi mengekstraknya selama kompilasi hanya untuk kenyamanan — itu selalu dapat dilakukan sebagai penguraian terpisah (dan pada kenyataannya, mungkin berakhir seperti itu, karena saya perlu melihat _semua_ dari mereka di peti dan kompilasi tambahan akan memecahkannya).

Saya ingin membuat makro prosedural yang didasarkan pada turunan serde (dan memanggil fungsi tokenstream serde secara langsung) tetapi tidak ada cara untuk mengatakan saya ingin menggunakan turunan serde sebagai perpustakaan daripada makro prosedural. Ini tidak eksklusif untuk mendapatkan makro, saya dapat melihat hal serupa yang diinginkan untuk makro prosedural 'normal' juga.

Satu-satunya solusi saya saat ini tampaknya adalah forking serde_derive.

Masalahnya adalah pesan kesalahan ini dari rustc:

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

Sangat mudah untuk menghapusnya dan membuatnya berfungsi, tetapi ada juga beberapa kerumitan yang saya tidak yakin bagaimana cara mengatasinya - peti makro prosedural mungkin ingin menggunakan proc-makro yang berasal dari peti makro prosedural lain, serta memanggil fungsi untuk menghasilkan turunan bagi pengguna hilir. Terlihat seperti apa? Apakah ada hal serupa seperti ini saat ini, di mana peti dapat dihubungkan dengan dua cara berbeda atas permintaan peti konsumsi?

@aidanhs

peti makro prosedural mungkin ingin menggunakan proc-makro yang berasal dari peti makro prosedural lain, serta memanggil fungsi untuk menghasilkan turunan untuk pengguna hilir. Terlihat seperti apa?

Anda tidak dapat mengakses fungsi (atau apa pun selain makro prosedural) dari peti proc-macro . Jika Anda ingin menggunakan fungsi TokenStream -> TokenStream dan makro prosedural yang sesuai, Anda harus meletakkan fungsi TokenStream -> TokenStream dalam peti terpisah, non- proc-macro , dan kemudian juga memiliki peti proc-macro yang hanya mendelegasikan fungsi tersebut.

RFC ini sebagian besar akan diterapkan setelah #40939 mendarat.

Berikan cara bagi penulis proc_macro untuk membuat perluasan yang menggunakan item dalam peti yang telah ditentukan foo tanpa mengharuskan pengguna makro untuk menyertakan extern crate foo; di akar peti

Misalkan saya ingin menyajikan satu peti, yang berisi item non-makro dan makro prosedural yang mengacu pada item tersebut. Ketika #40939 mendarat, apakah pola tiga peti ini akan menjadi cara idiomatis untuk mencapai tujuan ini?

  1. Letakkan semua item non-makro di foo_runtime
  2. Terapkan makro prosedural di foo_macros , mengacu pada simbol di foo_runtime seperlunya
  3. Tambahkan peti "faade" terakhir foo yang pub use s item dari foo_runtime dan foo_macros

    • Ini adalah satu-satunya peti yang akan diimpor langsung oleh pengguna

    • Ini berfungsi karena sistem kebersihan memperbaiki makro agar mengarah ke peti yang tepat

Saya bertanya karena kasus penggunaan saya melibatkan mengimpor dua peti , dan akan sangat bagus untuk kegunaan jika saya bisa lolos hanya dengan satu.

@lfairy Saya pikir pola "dua peti" akan menjadi cara idiomatis:

  1. Letakkan semua item non-makro di foo
  2. Terapkan makro prosedural di foo_macros , merujuk ke simbol di foo seperlunya, mis.
#[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 item dari foo_macros di foo .

Ini berfungsi karena sistem kebersihan memperbaiki makro agar mengarah ke peti yang tepat

Mengekspor ulang makro prosedural di peti yang berbeda tidak memengaruhi cara nama dari makro prosedural diselesaikan.

@jseyfried : Tahukah Anda apakah trik re-ekspor ini juga berfungsi dengan turunan khusus? Karena peti-peti ini memiliki batasan yang sama persis yaitu tidak dapat mengekspor barang apa pun.

@colin-kiegel
Peti turunan khusus hanyalah peti makro proc yang kebetulan hanya memiliki #[proc_macro_derive] s.
Dengan #[feature(proc_macro)] , Anda dapat mengekspor ulang turunan kustom dalam peti biasa, sama seperti Anda dapat mengekspor ulang makro proc lainnya.

@jseyfried Saya menyadari situasinya saat ini, saya mengajukan pertanyaan karena menurut saya itu tidak ideal dan berharap untuk berdiskusi tentangnya. Dalam situasi yang Anda gambarkan, 'mendelegasikan'/menggunakan kembali ke makro prosedural dari peti lain menjadi masalah meyakinkan penulis makro (dalam hal ini, serde) untuk membagi makro prosedural mereka menjadi dua peti. Jika saya dapat memanggil makro prosedural seperti fungsi normal, pembuat peti hulu bahkan tidak perlu tahu saya menggunakan peti mereka.

Yang mengatakan, saya mengenali bahaya kompatibilitas - tokentree yang tepat yang dihasilkan oleh makro menjadi bagian dari antarmuka yang stabil, jadi jika serde mengubah cara mereka menghasilkan Derive dalam versi tambalan dan saya telah menulis makro yang rapuh, makro akan rusak untuk setiap pengguna baru peti saya (berlawanan dengan makro rapuh dalam kasus saat ini, di mana dalam kasus terburuk itu hanya akan berfungsi untuk input tertentu, tetapi secara konsisten).

@jseyfried

Apakah ini menarik foo dari deplist kargo saat ini? Kedengarannya buruk (yaitu apakah ia akan melakukan sesuatu yang sangat bodoh jika ada 2 peti bernama foo ditautkan ke biner saat ini?).

@aidanhs Itu akan menjadi perubahan/penambahan bahasa utama yang akan menjamin RFC-nya sendiri.

@arielb1

Apakah ini menarik foo dari deplist kargo saat ini? Kedengarannya buruk

Ya -- sayangnya, nama extern crate dikutip tidak higienis, yaitu resolusinya tergantung pada nama peti yang berada dalam lingkup di mana makro prosedural digunakan. Kita dapat mengurangi ini menggunakan trik re-ekspor (yaitu mengekspor ulang foo_macros di foo sehingga kita tahu foo akan berada dalam cakupan), tetapi itu tidak melindungi terhadap kesalahan ambiguitas ketika ada dua peti bernama foo .

Saya pikir solusi terbaik di sini adalah menambahkan fase 1 (yaitu target wrt Host vs target) dependensi ke Cargo.toml untuk proc-macro melalui argumen baris perintah --target-extern . Ini akan memungkinkan kita untuk secara eksplisit mencantumkan nama extern crate dalam cakupan di dalam quote! .

@jseyfried

Idenya adalah bahwa peti proc-makro akan memiliki ketergantungan pada metadata "target"-nya, bukan?

@arielb1 Ya, persis.

RFC ini sebagian besar akan diterapkan setelah #40939 mendarat.

@jseyfried Seperti, siap distabilkan ketika PR itu mendarat? Jika tidak, apa yang akan tetap menghalangi stabilisasi? Saya hanya tidak ingin ini menjadi fitur lain di mana rasanya seperti kita mendapatkan 95% dari jalan menuju penerapan dan orang-orang menjadi bersemangat, dan kemudian semuanya mereda secara antiklimaks.

Seperti, siap distabilkan ketika PR itu mendarat?

Tidak, kami ingin mendapatkan pengalaman dengan API sebelum menstabilkan dan mungkin kebersihan bukti di masa mendatang untuk nama extern crate (yaitu mengatasi masalah ini yang ditunjukkan oleh @arielb1 ).

Kami mungkin ingin membuat perubahan besar pada API ini; @eddyb telah mengusulkan/mempertimbangkan untuk menggeneralisasi OpKind ke semua pohon token. Selain itu, kami mungkin mengubah cara kami menangani komentar dokumen, literal floating point, dll. Secara keseluruhan, API dalam PR ini belum cukup matang untuk mempertimbangkan stabilisasi.

@bstrie sayangnya RFC untuk mempercepat stabilisasi makro proc (dengan api terbatas di mana misalnya aliran token hanya dapat diakses melalui representasi string mereka) seperti stabilisasi makro turunan telah gagal: https://github.com/rust-lang/rfcs/ tarik/1913

@est31 Ditunda, lebih

API berbasis String berinteraksi buruk dengan makro deklaratif 2.0 dan sudah membatasi hari ini, bahkan tanpa makro 2.0 dan hanya dengan #[derive] s. Kami ingin menghindari proliferasi API berbasis String sebanyak mungkin untuk menghindari masalah saat orang bermigrasi ke makro 2.0.

Saya telah membuka masalah untuk #[proc_macro_attribute] tampaknya tidak diperluas pada metode sifat (mungkin item sifat secara umum?)

Karena sekarang ini adalah masalah pelacakan untuk peti proc_macro dan API barunya, saya pikir saya juga akan menuliskan beberapa pemikiran. Saya telah menerbitkan peti yang disebut proc-macro2 yang dimaksudkan untuk sama persis dengan peti di pohon proc_macro kecuali ia menyediakan kemampuan untuk dikompilasi pada Rust yang stabil. Itu kemudian juga memiliki kemampuan untuk menggunakan fitur untuk mengkompilasi pada Rust malam untuk mendapatkan manfaat dari informasi rentang yang lebih baik. Pustaka tersebut dimaksudkan untuk menjadi dasar bagi perpustakaan lain seperti syn , dan dalam pengembangan syn kami menemukan beberapa kekurangan yang mungkin ingin kami atasi di proc_macro secara langsung:

  • Tidak ada konstruktor Literal untuk beberapa jenis literal. Ini diselesaikan melalui stringifikasi diikuti dengan penguraian, tetapi akan sangat bagus untuk dapat membangun ini secara langsung tanpa harus melalui API string.

    • String mentah - r###" foo "###

    • String byte mentah - rb#" foo "#

    • Literal byte - b'x'

    • Komentar Doc - ini saat ini direpresentasikan sebagai token Literal .

  • Tidak ada cara untuk memeriksa Literal dan mengekstrak nilainya. Saat ini kami mengandalkan peti literalext untuk to_string literal dan menguraikannya kembali, tetapi informasi ini dalam teori sudah disimpan di Literal dan akan menyenangkan untuk dapat mengaksesnya.
  • Pemetaan token dalam beberapa kasus dapat dianggap agak aneh. Yaitu sekarang komentar doc dipetakan ke tipe Literal .

Saya percaya semua masalah lain yang dimulai di sini telah ditangani.

Saya mengalami kerusakan saat menguji dengan #![feature(proc_macro)] yang memengaruhi turunan khusus yang memiliki #[proc_macro_derive(foo, attributes(foo))] . Yaitu, turunan adat yang memiliki nama atribut yang sama dengan turunan adat. Salah satu peti tersebut adalah milik saya - turunan-kesalahan-rantai, yang memiliki #[derive(error_chain)] #[error_chain(...)] struct ErrorKind { ... } . Lain adalah turunan-baru, yang memiliki #[derive(new)] #[new] struct S; . Saya tidak tahu apakah ada orang lain.

Untuk kode seperti ini, kompiler mengeluh pada atribut kedua yang "foo" is a derive mode . Apakah ini disengaja atau bisa diperbaiki? Jika sengaja saya harus bersiap untuk mengganti nama turunan kebiasaan saya menjadi ErrorChain atau semacamnya.

@Arnavion
Ini disengaja secara umum -- karena proc_macro_attribute s harus diperluas sebelum diturunkan, jika new adalah proc_macro_attribute maka ekspansi akan menjadi ambigu. Dimungkinkan untuk secara khusus mengizinkan new menjadi proc_macro_derive , tapi saya tidak yakin itu sepadan (juga bisa menjadi bahaya kompatibilitas di masa depan).

Ini disengaja secara umum -- karena proc_macro_attributes harus diperluas sebelum diturunkan, jika new adalah proc_macro_attribute maka ekspansi akan menjadi ambigu.

Oke, saya akan mengganti nama #[derive(error_chain)] menjadi #[derive(ErrorChain)] .

Dimungkinkan untuk secara khusus mengizinkan new menjadi proc_macro_derive , tapi saya tidak yakin itu sepadan (juga bisa menjadi bahaya kompatibilitas di masa depan).

Tentu, saya tidak meminta new untuk menjadi casing khusus. Itu hanya contoh dari salah satu dari dua proc_macro_derive yang saya tahu yang rusak oleh ini.

@Arnavion Maaf, komentar terakhir saya tidak paling jelas -- saya tidak bermaksud khusus new secara khusus tetapi untuk mengizinkan #[derive(some_macro)] #[some_attr] struct S; ketika some_attr diselesaikan menjadi proc_macro_derive . Ketika some_attr diselesaikan menjadi proc_macro_attribute , ini harus berupa kesalahan ambiguitas; hari ini, ini adalah kesalahan ambiguitas jika some_attr diselesaikan ke makro apa pun.

Ya, saya mengerti.

( Saya harap ini adalah tempat yang tepat untuk pertanyaan seperti ini. )

Ini statusnya apa?

  • [ ] Berikan cara bagi penulis proc_macro untuk membuat perluasan yang menggunakan item dalam peti yang telah ditentukan foo tanpa mengharuskan pengguna makro untuk menyertakan extern crate foo; di root peti (PR #40939 ).

PR sudah mendarat, tapi kotaknya masih belum dicentang. @jseyfried menyebutkan sesuatu di sini dan sepertinya berhasil. Namun sepertinya tidak berfungsi dengan use sama sekali:

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

Apakah saya melewatkan sesuatu? Apa cara idiomatis untuk simbol use dari peti eksternal yang diimpor di makro?

Anda tidak dapat menggunakan use lihat https://github.com/rust-lang/rfcs/issues/959. Tetapi untuk makro, tidak ada kerugian untuk menggunakan jalur yang sepenuhnya memenuhi syarat setiap saat. (Kecuali untuk sifat, saya pikir)

@kering Terima kasih telah menautkan masalah lain ini. Kasus penggunaan saya adalah sebagai berikut:

Di makro saya, saya ingin membiarkan pengguna menulis sesuatu yang mirip dengan korek api. Secara khusus, pengguna menulis Term dan ini bisa berupa varian dari enum atau nama variabel sederhana yang mengikat nilai kecocokan. Untuk menulis beberapa kode semu dengan sintaks macro_rules! :

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

Sekarang saya ingin pengguna hanya dapat menentukan nama varian tanpa nama enum. Jadi saya akan memasukkan pernyataan use my_crate::AnEnum::*; dalam kode yang dihasilkan. Tetapi karena ini tidak mungkin (saat ini), saya perlu memeriksa sendiri apakah $matcher adalah varian dari enum atau tidak.

Semoga penjelasan saya dapat dimengerti. Saya hanya ingin memberikan kasus penggunaan lain untuk use dalam kode yang dibuat secara makro.

@LukasKalbertodt Bisakah Anda menggunakan my_crate::AnEnum::$matcher => {} di match ?
Tidak apa-apa, saya masalahnya - saya yakin kita perlu https://github.com/rust-lang/rfcs/issues/959 untuk itu.

@jseyfried Tidak: $matcher dapat berupa nama varian (dalam hal ini solusi Anda akan berfungsi) atau nama variabel sederhana seperti di match x { simple_var_name => {} } . Dalam kasus terakhir itu tidak akan berfungsi AFAICT. (btw, saya hanya ingin menyebutkan kasus penggunaan lain untuk menunjukkan bahwa menggunakan use itu penting)

@jseyfried

Ini disengaja secara umum -- karena proc_macro_attributes harus diperluas sebelum diturunkan, jika new adalah proc_macro_attribute maka ekspansi akan menjadi ambigu.

Oke, saya akan mengganti nama #[derive(error_chain)] menjadi #[derive(ErrorChain)] .

Tampaknya atribut turunan khusus juga bertentangan dengan makro macro_rules , alih-alih menimpanya seperti yang dilakukan turunan khusus berdasarkan pesanan impor. Artinya, kode ini mengkompilasi:

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

Hal ini sesuai dengan perilaku stabil saat Rust, dengan pengecualian bahwa (1) tidak bekerja di stabil. Saya bahkan telah secara eksplisit mendokumentasikan bahwa pengguna yang ingin menggunakan #[macro_use] dengan error-chain harus mengimpornya sebelum mengimpor derive-error-chain .

Tetapi bahkan jika saya mengganti nama turunan kustom menjadi ErrorChain untuk membuat (1) berfungsi dengan fitur proc_macro (yang sudah merupakan satu perubahan besar untuk kode stabil):

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

itu masih tidak dapat dikompilasi - atribut di (2) menghasilkan kesalahan: macro `error_chain` may not be used in attributes karena makro macro_rules tampaknya bertentangan dengan atribut yang didaftarkan oleh turunan khusus alih-alih ditimpa seperti dalam kasus pertama.

Jadi saya harus mengganti nama turunan kustom dan atributnya. Atribut digunakan lebih banyak (satu pada setiap varian enum) daripada turunan khusus (satu pada setiap enum), jadi ini adalah perubahan yang lebih besar dari yang saya harapkan. Saya mengerti bahwa ini adalah situasi rumit dari konstruksi saya sendiri (menggunakan kembali nama makro macro_rules untuk turunan kustom dan atributnya), tetapi ini juga kode yang telah dikompilasi secara stabil sejak turunan kustom stabil, jadi saya tidak punya alasan untuk berpikir itu akan menjadi masalah enam bulan kemudian.

Bisakah itu dibuat sedemikian rupa sehingga atribut turunan kustom menimpa makro macro_rules seperti halnya turunan kustom menimpa makro macro_rules ? Sebenarnya saya tidak melihat bagaimana mungkin ada ambiguitas di antara mereka, tetapi saya menganggap itu alasan yang sama seperti ketika makro macro_rules diimpor setelah turunan kustom dengan nama yang sama - bahwa semua makro dimasukkan ke dalam namespace yang sama tanpa mempertimbangkan jenis makronya.

Apakah ada "tempat" yang kurang formal untuk berbicara tentang makro proc? Suka saluran IRC #rust-proc-macro ? Saya ingin mengajukan pertanyaan kecil tentang fitur ini dari waktu ke waktu, tetapi rasanya salah untuk mengirim spam ke utas ini :see_no_evil: Dan di saluran #rust , kebanyakan orang belum bekerja dengan proc-makro dan terutama proc_macro API baru (karena tidak stabil dan sebagainya). Jadi: ada ide di mana untuk membahas topik ini?

@LukasKalbertodt #rust-internals , mungkin, atau hanya memulai utas baru di /r/rust.

TokenStream::from_str panik saat digunakan di luar makro prosedural (misalnya dalam skrip build):

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

Apakah mungkin/diinginkan untuk mengganti kepanikan ini dengan secara implisit membuat "sesi" dummy? Atau mungkin menambahkan API publik (dengan jalur menuju stabilisasi) untuk membuatnya?

Adakah yang melihat literatur tentang makro dari sistem lain? Saya ingin mendengar pendapat orang tentang ini. Saya akan berbicara tentang Skema di sini, karena itulah yang paling saya kenal.

Saya pribadi sedang mengerjakan implementasi syntax-rules untuk Skema R7RS pada proyek saya sendiri, dan saya telah menemukan bahwa syntax-case dapat menjadi dasar untuk mendukung sistem makro yang tidak higienis dan higienis ( defmacro dan syntax-rules ). GNU Guile melakukan ini. syntax-case juga memiliki dukungan untuk fender yang dapat melakukan validasi predikat tambahan pada daftar objek sintaks (atau, sesuatu di antara baris TokenStream dalam Skema). Saya dapat melihat bahwa Mark sedang dikerjakan, dan sepertinya itu terinspirasi oleh Bindings as Sets of Scopes .

Juga, haruskah kita juga mendiskusikan apakah komputasi arbitrer pada waktu kompilasi harus didukung? Racket sebenarnya mengambil pendekatan "fase" keseluruhan untuk berbagai hal, tampaknya, dengan begin-for-syntax memungkinkan untuk definisi dan perhitungan (?) pada tingkat waktu kompilasi selama ekspansi makro. .

Kontrol atas kebersihan sangat mungkin dilakukan dengan (datum->syntax <thing-to-copy-scope-from> <thing-to-apply-scope-to>) di Skema, memungkinkan Anda untuk keluar dari lingkup makro dan sebagai gantinya mengambil lingkup objek di luar lingkup langsung.

Ambil contoh ini dari The Scheme Programming Language, edisi ke-3. oleh R. Kent Dybvig (Skema Chez, sekarang di Cisco Systems): http://www.scheme.com/tspl3/syntax.html . Contoh menunjukkan (include "filename.scm") sebagai makro syntax-case , dan memungkinkan penerjemah menggunakan makro untuk menyiapkan runtime untuk membaca dari file dan melanjutkan evaluasi. Pertanyaan yang lebih dalam di sini adalah apakah kita ingin sistem makro-makro mengizinkan hal-hal seperti itu terjadi pada waktu ekspansi makro, dan memicu perhitungan waktu kompilasi seperti memicu impor file (walaupun, ini tampaknya terjadi pada fungsionalitas kompiler langsung, jadi mungkin kita tidak ingin melakukan ini).

Apa yang seharusnya menjadi batas makro? Saya akan membayangkan bahwa Rust, ingin mengurangi waktu kompilasi, ingin membatasi evaluasi waktu kompilasi (dan terutama menghindari loop tak terbatas). Racket telah mengambil pendekatan "menara pembuat dan ekspander" dengan fase seperti yang dirujuk dalam Lisp in Small Pieces. Apakah kita ingin mengizinkan hal-hal seperti mengizinkan akses ke API waktu kompilasi untuk melakukan I/O file dan komputasi rekursif terbatas? Haruskah kita mengizinkan hal-hal seperti makro prosedural dapat mengubah spesifikasi spreadsheet CSV menjadi pernyataan sakelar?

Saya ingin mendengar tentang sistem lain! Saya mendengar Template Haskell memiliki pendekatan yang menarik dengan tipe yang terdefinisi dengan baik untuk mewakili AST mereka, dan kemalasan di Haskell dapat menggantikan banyak penggunaan makro untuk struktur kontrol.

Maaf jika saya melangkah keluar dari barisan.

Apa yang seharusnya menjadi batas makro?

Untuk makro prosedural , yang dibahas dalam masalah ini, tidak ada . Makro prosedural adalah ekstensi kompiler. Ini dapat mengambil sedikit kode C++, menjalankannya melalui dentang dan menambahkan objek yang dihasilkan ke kompilasi. Diperlukan beberapa SQL, kueri database untuk menemukan jenis hasil yang sesuai dan menghasilkan kumpulan hasil yang sesuai. Itu adalah kasus penggunaan aktual yang ingin dilakukan orang!

Perhatikan, bahwa Rust memiliki sistem makro lain . Pembaruannya disetujui sebagai RFC 1584 dan implementasinya dilacak oleh https://github.com/rust-lang/rust/issues/39412.

@VermillionAzure , dari tampilan cepat di formulir Skema yang Anda rujuk:

macro_rules , dan pembaruannya per RFC 1584 , mirip dengan syntax-rules . Jika Anda memiliki saran untuk meningkatkannya, https://github.com/rust-lang/rust/issues/39412 mungkin adalah tempat terbaik untuk mendiskusikannya.

Proc-makro, tentang masalah ini, seperti bentuk umum dari define-syntax . Dan RFC ini ( 1566 ) dengan sangat sengaja tidak mendefinisikan sesuatu seperti syntax-case . Hanya antarmuka untuk memanggil fungsi untuk mengubah aliran token.

Antarmuka didefinisikan sedemikian rupa sehingga sesuatu seperti syntax-case dapat diimplementasikan dalam peti (perpustakaan) terpisah dan tujuannya adalah untuk melakukannya dengan cara itu. Jika Anda sangat ingin, jangan ragu untuk bermain-main. Prototipe apa pun dan laporan tentang seberapa mudah atau sulitnya menggunakan API pasti akan diterima.

Saya pikir idenya adalah, mendefinisikan makro seperti fungsi, seperti di cadel, tetapi memiliki makro, yang mengembalikan makro, yang didefinisikan oleh macro_rules! .

Jadi berikut ini akan setara:

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

Begitulah syntax-rules dan syntax-case tampaknya bekerja dalam skema.

@VermillionAzure
Apakah ini, apa yang Anda inginkan?

@porky11 Tidak, sepertinya tidak. Saya hanya ingin melihat apakah makro Skema akan menjadi ide yang relevan untuk ditambahkan ke diskusi -- jelas bahwa karena makro prosedural dimaksudkan untuk menjadi jauh lebih kuat daripada sistem makro syntax-case dalam Skema, itu sepele untuk menerapkan semua sistem makro dalam hal kekuatan sewenang-wenang yang disediakan di sini.

@jan-hudec Apakah bijaksana untuk mengizinkan perhitungan sewenang-wenang sebagai ekstensi kompiler tanpa jaminan keamanan apa pun? Saya benar-benar terkesima dengan gagasan bahwa makro prosedural akan menjadi sangat kuat di sini, tetapi apakah pengguna potensial Rust akan menganggap ini sebagai kerugian menggunakan paket? Saya bukan ahli keamanan dengan cara apa pun, tetapi tidak bisakah kerentanan di perpustakaan apa pun yang digunakan dalam ekstensi kompiler dapat dengan mudah digunakan untuk mengubah kompiler Rust secara jahat menjadi vektor serangan? Selain itu, jika ada bug yang terjadi di perpustakaan yang digunakan dalam makro prosedural (misalnya segfault dipicu oleh kode perpustakaan C yang buruk), apakah ini berarti bahwa segfault akan menetes dan membuat kompiler gagal tanpa pesan kesalahan yang tepat?

Apakah ada cara untuk merangkum kesalahan yang terjadi di makro prosedural dengan cara yang tidak akan memengaruhi bagian lain dari kompiler?

Ide lain: kapan makro prosedural dijalankan? Jika makro prosedural dapat berinteraksi dengan kode yang memiliki efek samping yang mungkin relevan (misalnya berkomunikasi dengan server eksternal stateful, mengubah database SQL eksternal, mendapatkan kunci keamanan untuk masuk ke sistem eksternal), bukankah itu berarti bahwa urutan makro prosedural mana yang dipicu oleh proses kompilasi itu penting?

Paket @VermillionAzure Cargo sudah dapat memiliki skrip build yang mengeksekusi kode arbitrer pada waktu kompilasi, jadi makro prosedural tidak memperburuk keadaan di depan itu: Anda sudah perlu memercayai dependensi Anda. (Ini dibuat lebih mudah dengan crates.io menjadi tidak dapat diubah/hanya append, dan dependensi tidak diperbarui secara otomatis jika Anda memiliki file Cargo.lock : Anda hanya perlu memercayai versi tertentu.) Dan bahkan jika skrip build tidak ada, dependensi Anda masih dapat secara alami mengeksekusi kode arbitrer saat run-time. Apakah waktu kompilasi jauh lebih buruk?

Diskusi ini membuat saya memikirkan masalah yang terkait, tetapi berbeda.

Misalkan sebuah peti mendefinisikan dua makro proc: foo!() menulis file sementara, dan bar!() membaca file yang sama. Konsumen peti ini memanggil foo!() dan bar!() dalam modul yang sama. Kemudian, apakah kompilasi berhasil atau tidak akan tergantung pada foo!() atau bar!() mana yang diekspan terlebih dahulu. Urutan ini ditentukan oleh implementasi, dan jika cukup banyak orang yang menulis kode seperti ini, dapat menjadi standar de-facto.

Saya tidak yakin seberapa besar masalah ini. Hanya khawatir tentang apakah ini akan menyebabkan pengulangan kesalahan pemesanan bidang struct.

@SimonSapin

Meskipun saya setuju dengan posisi Anda, saya harus menunjukkan bahwa ada satu perbedaan signifikan antara eksekusi waktu kompilasi dan eksekusi runtime:

Ini memberikan model ancaman yang berbeda karena hal-hal cenderung dikompilasi sekali dan kemudian disebarkan ke banyak mesin. (Misalnya. Memanfaatkan kurangnya perhatian pengelola ditambah kekurangan sandboxing pada cluster build distro Linux.)

@lfairy Ya, ini adalah masalah persis yang dimiliki Racket lebih dari satu dekade lalu pada tahun 2002. Matthew Flatt, kontributor tertinggi Racket, membuat makalah berjudul "Makro yang Dapat Disusun dan Dapat Disusun: Anda Ingin Kapan? . R. Kent Dybvig, yang bekerja di Chez Scheme, juga menulis makalah tentang fase evaluasi untuk perpustakaan/modul di "Pentahapan Tersirat di Perpustakaan R6RS" .

@SimonSapin Compile-time berpotensi jauh lebih buruk. Jika kompiler Anda mogok secara acak atau melakukan perilaku jahat yang dipicu oleh kompiler, maka saya berani bertaruh bahwa seseorang pada akhirnya akan menulis posting Reddit besar yang akan berjudul "Modul Karat Secara Inheren Tidak Aman" atau sesuatu seperti itu.

@VermillionAzure , saya tidak membaca artikel dengan sangat hati-hati, tetapi saya tidak berpikir mereka relevan untuk diskusi, karena masalah yang dihadapi oleh Rust sangat berbeda dari masalah yang dihadapi oleh Skema.

Dalam Skema satu perpustakaan dapat menyediakan fungsi dan makro, sehingga kompiler harus memilah dengan benar fungsi mana yang memerlukan waktu kompilasi dan mana yang membutuhkan waktu proses. Namun, di Rust sebuah peti menyediakan makro prosedural, atau fungsi runtime, jadi pembagian ini (untuk saat ini) jelas.

(Perhatikan bahwa peti yang menyediakan fungsi runtime juga dapat menyediakan makro berbasis aturan (higienis), tetapi itu adalah mekanisme terpisah di Rust)

Masalah yang dibicarakan @lfairy adalah salah satu urutan eksekusi fungsi expander. Di Rust, kompilasi mungkin paralel untuk file terpisah dan mungkin tambahan, sehingga urutan eksekusi ekspander tidak ditentukan. Tetapi apakah kedua artikel itu benar-benar membahasnya? Saya tidak melihatnya.

@jan-hudec Ya, saya rasa Anda benar. Tetapi urutan evaluasi pasti akan menjadi masalah jika efek samping diizinkan pada waktu kompilasi, kecuali jika Anda dapat menjamin modul tertentu tidak menghasilkan efek samping. Apakah modul "bisa mengetik?"

Saya pikir makro prosedural "mungkin tidak boleh" memiliki efek samping karena beberapa detail (lihat di bawah) tidak dapat diandalkan, tetapi kami kemungkinan tidak akan memiliki mekanisme seperti sistem tipe dalam bahasa untuk memaksa mereka menjadi murni fungsional.

Detail ini mencakup pengurutan eksekusi dan konkurensi dibandingkan dengan makro proc lainnya, dan apakah proc-makro dieksekusi ulang dalam build inkremental. Untuk yang terakhir, kami mungkin ingin menambahkan sesuatu untuk mendeklarasikan dependensi yang mirip dengan rerun-if-changed dalam skrip build. Dan seperti skrip build, deklarasi ini mungkin tidak lengkap atau bermasalah. Kami tidak dapat mencegah semua bug secara statis.

Saya pikir kita harus menghindari jaminan apa pun tentang efek samping (yaitu peti makro proc tidak diizinkan untuk mengandalkan efek samping yang bekerja, juga tidak diizinkan untuk mengandalkan dipicu untuk apa pun selain perubahan kode dalam modul di mana mereka diterapkan ( jadi, tidak ada negara global).

Kami kemudian dapat melonggarkan persyaratan ini dengan cara menentukan rerun-if-changed dan hal-hal lain.

(Saya punya proposal keamanan makro skrip / proc umum setengah matang yang akan sedikit membantu di sini, tetapi saya belum benar-benar menulisnya)

Makro proc IMO / turunan khusus harus dimasukkan ke dalam lingkungan kotak pasir tanpa I/O atau koneksi lain ke luar dan dievaluasi oleh miri, mungkin dengan JIT cranelift.

@est31 itu ide yang bagus tapi hal-hal seperti diesel infer_schema! sudah
ada, bindgen perlu membaca file dan menjalankan program, bahkan menyertakan! dan
env! menggunakan I/O.

Pada 9 November 2017 06:19, "est31" [email protected] menulis:

Makro proc IMO / turunan khusus harus dimasukkan ke dalam lingkungan kotak pasir
tanpa I/O atau koneksi lain ke luar dan dievaluasi oleh
miri, mungkin dengan JIT cranelift.


Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub
https://github.com/rust-lang/rust/issues/38356#issuecomment-343124957 ,
atau matikan utasnya
https://github.com/notifications/unsubscribe-auth/AAC3n5VOPdKBsu81Sp3tp2XlIQ05L865ks5s0t_PgaJpZM4LMWlc
.

Sepertinya #40939 dan #44528 sudah bergabung... @jseyfried bisa perbarui checklistnya?

@mark-im diperbarui.

Bisakah makro prosedural menghasilkan makro prosedural?

@VermillionAzure Saya belum mencobanya, tetapi saya tidak melihat alasan mengapa mereka tidak bisa. Jika tentu saja, seperti makro proc yang menghasilkan kode "run-time", mereka harus berada di peti yang terpisah dari peti tempat mereka digunakan.

Dalam syn kami mengalami batasan proc_macro::TokenNode hari ini -- pembatas blok { ... } dikaitkan dengan hanya satu Span di input TokenStream sehingga tidak ada cara untuk memicu kesalahan yang hanya menunjuk ke } penutup. Rustc tampaknya tidak memiliki batasan ini.

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

Hal terbaik yang dapat kita lakukan dalam makro proc adalah menunjuk ke token terakhir di dalam blok, menunjuk ke seluruh blok, atau menunjuk ke token berikutnya setelah blok, tidak ada yang benar-benar Anda inginkan untuk kesalahan seperti di atas.

Solusi umum adalah memiliki Span::start dan Span::end mengembalikan 1 karakter Span alih-alih LineColumn seperti yang mereka lakukan saat ini, lalu buka cara untuk pergi dari Span ke baris pertama/kolom rentang.

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

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

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

Menyebutkan @abonander yang menambahkan API itu di #43604.

memiliki Span::start dan Span::end mengembalikan Span 1 karakter alih-alih LineColumn seperti yang mereka lakukan saat ini, kemudian memaparkan cara untuk beralih dari Span ke baris pertama/kolom rentang.

Itu akan membuat Span mengadopsi perilaku khusus yang dibutuhkan daftar yang dibatasi, tetapi akan salah untuk semua rentang lainnya. Umumnya tidak benar. Pertimbangkan untuk mendapatkan rentang untuk ekspresi seperti foo(hi) dengan menggabungkan hal-hal. Sekarang Anda ingin menunjuk ke foo dan mengambil sp.begin() , tetapi sp.begin() hanya menunjuk ke karakter pertama foo .

Saya pikir solusi yang lebih baik adalah menambahkan dua rentang ke proc_macro::TokenNode::Group atau mengizinkan pembuatan rentang sewenang-wenang.

Span::begin / end jenis pengembalian mungkin harus berubah: https://github.com/rust-lang/rust/pull/43604#issuecomment -327643229

Saya mencoba untuk mendapatkan Span::def_site() untuk menyelesaikan hal-hal terhadap apa yang ada dalam lingkup makro prosedural saya. Apakah saya salah paham bagaimana ini seharusnya bekerja?

Kode yang hampir sama berfungsi jika saya menggunakan Span::call_site() dan MySend didefinisikan di main.rs, seperti yang saya harapkan. Belum bisa membuatnya bekerja dengan def_site() sekalipun.

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

Melacak ini di sisi Syn: https://github.com/dtolnay/syn/issues/290.

@dtolnay
Masalahnya di sini adalah bahwa MySend diimpor pada fase 0 (yaitu untuk arsitektur host saat kompilasi silang), jadi tidak tersedia di fase 1 (yaitu saat kompilasi untuk arsitektur target).

Solusinya di sini adalah mengizinkan peti proc-makro memiliki dependensi fase 1 (arsitektur target) sehingga kami dapat mengimpor item fase 1 ke dalam cakupan.

Hari ini, solusinya adalah kembali:

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

Anda juga dapat membuat ini secara manual, saya hanya menggunakan quote! untuk kenyamanan.

Karena kebersihan, dummy / std / MySend tidak akan pernah bertabrakan dengan apa pun dalam ruang lingkup, jadi misalnya aman untuk menggunakan makro ini lebih dari sekali dalam modul yang sama, aman untuk ident menjadi "Kirim Saya", dll.

Masalah ini, serta kebutuhan dan solusi untuk mod dummy , dijelaskan lebih detail di https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Sayangnya, sampai dependensi fase 1 diimplementasikan, ini akan menjadi tidak ergonomis.

Terima kasih @jseyfried! Itu bekerja. Beberapa pertanyaan lanjutan:

  • Dalam kode di komentar saya sebelumnya, jika saya mengubah impl_mysend_for untuk menghasilkan impl untuk Send alih-alih MySend maka semuanya dikompilasi. Untuk Send penyelesaian ini dan mengapa tidak mencapai perbedaan fase 0 vs fase 1? Apakah ini bekerja dengan sengaja atau tidak sengaja?

  • Apa lagi dalam lingkup yang dapat digunakan oleh token def_site() , seperti Send ?

  • Jika MySend perlu berasal dari perpustakaan (seperti bayangkan kita menurunkan serde::Serialize ) maka pengguna akhir masih membutuhkan serde di Cargo.toml mereka, meskipun kita tidak membutuhkan mereka untuk menulis extern crate serde . Apakah mungkin untuk membuat extern crate dengan ident def_site() menyelesaikan terhadap Cargo.toml makro prosedural, dan extern crate dengan ident call_site() menyelesaikan terhadap hilir kargo.toml?

Untuk peti eksternal, saya berasumsi bahwa peti perlu disediakan secara eksplisit untuk fase 1 oleh proc macro.

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

@dtolnay

Dalam kode di komentar saya sebelumnya, jika saya mengubah impl_mysend_for untuk menghasilkan impl untuk Kirim alih-alih Kirim Saya maka semuanya dikompilasi. Kirim ke mana penyelesaian ini dan mengapa tidak mencapai perbedaan fase 0 vs fase 1? Apakah ini bekerja dengan sengaja atau tidak sengaja?

Pertanyaan bagus. Saat ini, pendahuluan berada dalam ruang lingkup di situs definisi (kecuali peti proc-makro adalah #![no_implicit_prelude] ) dan ini adalah kecelakaan (dalam beberapa hal) karena perbedaan fase 0 vs fase 1 seperti yang Anda tunjukkan .

Namun, untuk ergonomi, saya pikir fase 1 harus secara implisit berisi std di akar proc-makro (sehingga Anda selalu dapat quote!(use std::...); ) dan pendahuluan untuk kenyamanan/ergonomi dan karena ini sudah tersirat di fase 0. Akan ada PR untuk menambahkan std di root di fase 1 segera.

Apa lagi dalam cakupan yang dapat digunakan oleh token def_site() saya, seperti Kirim?

Selain pendahuluan dan (segera) std seperti dibahas di atas, hal-hal lainnya hanya dalam lingkup dalam fase 1 adalah proc-macro sendiri (bukan proc-makro fungsi, yang fase 0).

Sebagai contoh,

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

Apakah mungkin untuk membuat peti eksternal dengan ident def_site() diselesaikan terhadap Cargo.toml makro prosedural, dan peti eksternal dengan ident call_site() diselesaikan terhadap Cargo.toml hilir?

Ya, kecuali saya percaya peti eksternal dengan Span::def_site() harus diselesaikan terhadap dependensi fase 1 (target) dari makro prosedural Cargo.toml -- dependensi fase 0 hari ini ditautkan ke perpustakaan yang dikompilasi untuk platform Host . Karena dependensi fase 1 belum ada, nama peti eksternal diselesaikan secara tidak higienis, yang menjengkelkan seperti yang Anda tunjukkan.

Setelah kita memiliki dependensi fase 1, kita tidak perlu mengutip extern crate s di setiap ekspansi untuk memulai, jadi ini bukan masalah. Namun, kami masih harus memperbaikinya -- rencana saat ini adalah mencoba menyelesaikan terhadap dependensi target peti proc-makro terlebih dahulu dan kemudian kembali ke resolusi tidak higienis dengan siklus peringatan prioritas rendah untuk menghindari churn.

Untuk peti eksternal, saya berasumsi bahwa peti perlu disediakan secara eksplisit untuk fase 1 oleh proc macro.
#[proc_macro_derive(Serialize, attributes(serde), crates(serde))]

Menarik, kita bisa menerapkannya dengan cara ini.

Saya malah berpikir bahwa peti fase 1 akan dideklarasikan di root peti proc-makro (misalnya #[phase(1)] extern crate foo; ) sehingga akan tersedia secara otomatis di semua makro proc (misalnya quote!(use foo::bar); ). Karena extern crate tetap akan keluar, kita dapat menghindari mendeklarasikan peti fase 1 sama sekali -- semua dependensi target dari Cargo.toml akan secara otomatis berada dalam cakupan di root peti proc-makro di fase 1.

Dalam kode saya, saya menemukan bahwa saya tampaknya menggunakan rentang untuk dua tujuan: untuk mengontrol resolusi nama, dan untuk mengontrol pesan kesalahan. Apakah keduanya terhubung secara tak terpisahkan, atau mungkinkah membuat rentang yang menggabungkan aspek resolusi nama dari satu rentang dengan lokasi pesan kesalahan baris/kolom dari rentang yang berbeda? Saya berharap ini menjadi kebutuhan bersama.

Untuk lebih spesifik, saya memiliki sifat yang dibawa ke dalam lingkup def_site dari turunan kustom saya dan saya ingin memanggil metode sifat pada bidang struct pengguna. Jika jenis bidang tidak menerapkan sifat yang benar, saya ingin pesan kesalahan menggarisbawahi bidang struct yang sesuai.

Saya dapat menghasilkan pemanggilan metode dengan rentang def_site yang dikompilasi dan dijalankan tetapi sayangnya pesan kesalahan selalu menunjuk ke atribut turunan seperti yang kita lihat dengan Macros 1.1.

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

Atau saya dapat menghasilkan pemanggilan metode dengan rentang yang sama dengan ident atau tipe bidang struct, yang menunjukkan garis bawah yang tepat tetapi gagal untuk menyelesaikan sifat dalam ruang lingkup di def_site saya.

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

Bagaimana saya bisa menyelesaikan dengan benar dan menunjukkan kesalahan seperti yang saya inginkan?

@dtolnay Itu poin yang bagus, terima kasih.

Saya pikir cara yang tepat untuk memperbaiki https://github.com/rust-lang/rust/issues/46489 mungkin dengan membuatnya sehingga token #[derive(…)] yang dihasilkan memiliki name- resolution-spans yang sama scope sebagai definisi tipe, dan error-messages-spans pada permintaan makro quote! {} yang membuatnya.

Bagaimana ceritanya dengan kebersihan saat ini? Saya memiliki fungsi seperti makro prosedural yang dulu berfungsi (4 bulan yang lalu) tetapi pada rustc 1.24.0-nightly (b65f0bedd 2018-01-01) ia mengeluh argumen tidak dapat ditemukan dalam ruang lingkup.

Maaf, seharusnya mencari pelacak masalah terlebih dahulu, sepertinya saya baru saja menekan https://github.com/rust-lang/rust/issues/46489.

Saya mengajukan #47311 yang saya yakini saat ini memblokir implementasi yang benar dari turunan(Deserialize). Makro prosedural tidak dapat membuat struktur yang memiliki bidang pribadi.

Diarsipkan lain, #47312 di mana akses ke bidang struct tuple yang tidak disebutkan namanya seperti self.0 memiliki persyaratan yang berbeda pada rentang token . daripada akses ke bidang struct bernama seperti self.x .

47311 dan #47312 masing-masing diperbaiki di #48082 dan #48083.

Saya memiliki dua PR di atas yang menunggu ulasan/komentar.

Sepertinya https://github.com/rust-lang/rust/pull/41029 sudah selesai sekarang?

PR itu ditinggalkan tetapi dihidupkan kembali dan terus dikerjakan di #48465. Saat ini menunggu di Kawah.

@petrochenkov @nrc

Melihat syntax::ext::expand , tampaknya proc_macro_attribute s saat ini tidak diproses dalam beberapa konteks (tidak lengkap):

  • di blok ( fold_block() adalah noop)
  • pada pernyataan/ekspresi (#41475, #43988)
  • di dalam blok extern {} (#48747)

RFC 1566 tidak mencantumkan jenis simpul AST tertentu yang dapat diterapkan makro atribut, menyarankan bahwa mereka harus berlaku untuk apa saja. Tapi itu bisa sedikit konyol jadi kita harus dengan jelas menetapkan apa yang perlu diproses tetapi tidak, dan di mana atribut tidak boleh diizinkan tetapi saat ini mungkin (#43988)

@abonander maksudnya adalah bahwa atribut makro proc dapat digunakan di mana saja atribut biasa berada dan tidak di tempat lain, yang menurut saya harus mencakup semua hal di atas (walaupun beberapa tidak stabil, dan jika kita menstabilkan makro proc, kita harus berhati-hati untuk hanya menstabilkan penggunaan yang stabil untuk atribut lain).

@nrc apakah ada di mana saja yang menyebutkan lokasi tersebut karena referensi hanya mengatakan bahwa atribut dapat diterapkan ke item apa pun. Namun, saya hampir yakin bahwa atribut lint dapat diterapkan ke blok dan pernyataan juga.

@nrc ada di mana saja yang menyebutkan lokasi tersebut karena referensi hanya mengatakan bahwa atribut dapat diterapkan ke item apa pun. Namun, saya hampir yakin bahwa atribut lint dapat diterapkan ke blok dan pernyataan juga.

Tidak ada afaik - ada RFC yang diterima dan tanda fitur yang tidak stabil untuk atribut pada ekspresi apa pun, tetapi saya pikir kami hanya menstabilkan pernyataan dan blok. Referensi kehabisan data.

Masalah ini:

Pemeriksaan stabilitas (proc-)makro (masalah #34079).

sekarang ditutup proc-makro WRT. PR saya tidak menambahkan pemeriksaan stabilitas untuk makro Macros 2.0, itulah sebabnya masalah ini masih terbuka (meskipun mungkin seharusnya hanya masalah baru saja).

@rfcbot menggabungkan

Saya ingin mengusulkan subset cerita makro 2.0 distabilkan sebagai makro 1.2 untuk rilis Rust 1.28. Rust 1,28 masuk setiap malam pada 10 Mei 2018 (~2,5 minggu sejak penulisan ini) dan akan menjadi stabil pada 2 Agustus 2018. Saya pikir FCP dapat selesai sebelum batas 10 Mei untuk 1,27 memasuki beta, tetapi saya ingin menahan matikan semua stabilisasi di sini sampai setelah batas itu terjadi dan tunda ini ke rilis 1,28.

Ini telah dibahas di internal baru-baru ini bersama dengan sejumlah masalah yang didaftarkan oleh @petrochenkov dan yang harus diperbaiki sekarang (tetapi belum dirilis di malam hari). Saya pikir akan membantu untuk rekap di sini jadi ini secara konkret adalah bagian yang akan distabilkan.

Ingat meskipun bahwa ini adalah subset . Fungsionalitas yang hilang di sini tidak berarti tidak akan pernah distabilkan atau dihapus dari kompiler. Alih-alih, fungsi ini akan tetap tidak stabil setelah usulan stabilisasi ini untuk distabilkan di kemudian hari.

Makro dan sistem modul

Terutama dicakup oleh https://github.com/rust-lang/rust/issues/35896 dan sekarang
setelah menyelesaikan FCP-nya, ide utamanya adalah Anda dapat menggunakan pernyataan use untuk
impor makro. Misalnya kode seperti ini:

use some_proc_macro_crate::bar;

#[bar]
fn baz() {}

atau

use some_proc_macro_crate::bar;
bar!();

atau bahkan

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

Ini memperkenalkan namespace ketiga di Rust (selain nilai/tipe
namespace), ruang nama makro. Atribut, macro_rules, dan prosedural
makro semua berada di namespace maro.

Perbedaan dari sistem modul full-blown adalah hanya satu elemen jalur akan diizinkan untuk dipanggilmakro .
Misalnya #[foo::bar] atau ::bar::baz!() tidak akan diizinkan. Ini
pembatasan dapat dicabut suatu hari tetapi ini adalah rute konservatif yang baik untuk
dimulai dari.

Di mana ekspansi bisa terjadi?

Atribut hanya dapat diterapkan ke non-modulitem .
"item" di sini mencakup hal-hal seperti item sifat, item impl, dan modul asing
item. Perluasan modul belum akan stabil karena kebersihan dan
konsekuensi implementasi. Terserah untuk menentukan dan menstabilkan ini pada a
nanti.

Pernyataan dan makro atribut ekspresi belum akan stabil. Ini adalah
terutama karena kebutuhan nyata untuk kebersihan di tingkat ekspresi (sebagai
bertentangan dengan tingkat item). Ini dibiarkan stabil di kemudian hari.

Akhirnya, makro atribut harus memiliki argumen di dalamnyapembatas .
Misalnya #[foo] , #[foo(bar)] , dan #[foo { bar baz ... @ | ^ hello }]
adalah seruan yang valid. Doa seperti #[foo = "baz"] , #[foo bar] , atau
#[foo ... = ( baz )] awalnya tidak akan stabil.

Seperti apa makro prosedural itu?

Seperti turunan khusus, mereka didefinisikan dalam peti tipe peti proc-macro .
Makro dan atribut prosedural didefinisikan seperti ini:

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

Bagaimana dengan kebersihan?

Di atas terlihat bahwa atribut khusus dan makro hanya dapat diperluas di
konteks item , terutama hanya menghasilkan node AST baru yang merupakan item. Ini
berarti kita hanya perlu khawatir tentang kebersihan menghasilkan item AST baru
node.

Item baru akan memiliki kebersihan yang sama seperti macro_rules! hari ini. Mereka akan
tidak higienis. Item baru yang ditambahkan ke AST akan memasuki namespace yang sama dengan
item lain dalam modul.

proc_macro API.

Untuk mengaktifkan semua ini, luas permukaan berikut akan distabilkan untuk:
peti proc_macro :

pub struct TokenStream(_);

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

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

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

pub mod token_stream {
    pub struct IntoIter(_);

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

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

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

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

pub struct Span(_);

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

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

pub struct Group(_);

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

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

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

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

pub struct Term(_);

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

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

pub struct Op(_);

pub enum Spacing {
   Alone,
   Joint,
}

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

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

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

pub struct Literal(_);

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

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

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

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

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

Informasi lebih lanjut tentang API ini dapat ditemukan secara online atau dalam versi aslinya PR

Strategi pengujian

Sistem makro 1.1 dan makro 2.0 telah banyak di-dogfood di seluruh
ekosistem untuk beberapa waktu sekarang. Khususnya seluruh proposal ini juga
diuji secara ekstensif melalui rilis 0.3 dari peti proc-macro2 sebagai
serta peti syn . Selama pengujian sejumlah bug telah
diidentifikasi dan diperbaiki dan sistem saat ini terasa cukup kuat untuk mulai
stabil. (bukan untuk mengatakan itu bebas bug!)

Anggota tim @alexcrichton telah mengusulkan untuk menggabungkan ini. Langkah selanjutnya adalah peninjauan oleh sisa tim yang ditandai:

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

Tidak ada kekhawatiran saat ini terdaftar.

Setelah mayoritas pengulas menyetujui (dan tidak ada yang keberatan), ini akan memasuki periode komentar terakhirnya. Jika Anda menemukan masalah besar yang belum diangkat pada titik mana pun dalam proses ini, silakan angkat bicara!

Lihat dokumen ini untuk info tentang perintah apa yang dapat diberikan oleh anggota tim yang ditandai kepada saya.

cc @rust-lang/compiler, kalian semua yang saya tahu juga sangat tertarik dengan ini dan jangan ragu untuk mengajukan keberatan. Jika Anda memiliki keberatan pemblokiran, saya juga dapat mendaftarkannya untuk Anda

Sepertinya, menggunakan API yang disediakan yang diusulkan untuk stabilisasi, makro proc dapat dengan mudah menghasilkan semua jenis token, atau menyalinnya dari input ke output, tetapi tidak dapat dengan mudah memeriksa aliran token bahkan pada tingkat yang dangkal. Misalnya, Literal tidak mengimplementasikan Eq atau PartialEq . Ada alasan khusus untuk itu? (Dan bahkan itu hanya akan memungkinkan perbandingan dengan nilai konstan yang ditentukan, daripada mengekstraksi nilai dan memprosesnya dalam kode.)

Di dalam implementasi makro proc, diberi TokenStream , apa yang dapat dilakukan makro proc untuk mengintrospeksi literal? Atau, dalam hal ini, ekstrak nilai satu? Apakah ini belum didukung? Apakah ada rencana untuk mendukungnya di masa depan?

(Saya tidak mencoba untuk memblokir stabilisasi subset yang diusulkan; Saya hanya ingin lebih memahami subset itu dan fitur yang dimaksudkan.)

@alexcrichton Item baru akan memiliki kebersihan yang sama dengan macro_rules! lakukan hari ini. Mereka akan
tidak higienis. Item baru yang ditambahkan ke AST akan memasuki namespace yang sama dengan
item lain dalam modul.

Saya tidak berada di tim inti Rust, dan saya belum sepenuhnya melihat semua diskusi sebelumnya, tetapi ini terdengar sangat buruk bagi saya. Bagaimana jika makro ingin menghasilkan item pembantu yang hanya dapat diakses oleh makro?

Daripada membuang kebersihan, saya pikir lebih baik untuk menegakkan kebersihan 100% penuh, tetapi memberikan cara bagi makro untuk secara eksplisit memilih keluar dari kebersihan untuk variabel tertentu.

@joshtriplett Anda akan menggunakan tampilan impl untuk Literal.

@joshtriplett ya seperti yang disebutkan @dtolnay Anda akan menggunakan Display yang merupakan dasar peti seperti literalext . Secara umum API dimaksudkan untuk menjadi "minimal", bukan API kelas satu yang memiliki semua lonceng dan peluit. Itu kemungkinan akan datang nanti!

Putaran stabilisasi ini dimaksudkan untuk menjadi "minimal maksimal" dalam arti menyediakan fungsionalitas paling sedikit untuk mencakup semua kasus penggunaan (alias Display untuk Literal dan tidak ada yang lain untuk menafsirkannya ).

@Pauan itu tidak bagus, ya, tapi itu sama persis dengan macro_rules! yang telah stabil selama bertahun-tahun sekarang dan bekerja dalam banyak konteks yang berbeda. Kami ingin mengaktifkan kebersihan dan perawatan yang lebih baik di sini, tetapi kami belum cukup siap. Konstruktor Span::call_site() adalah lynchpin di sini di mana dengan menggunakan itu Anda meminta "tidak ada kebersihan". Akhirnya kami akan menstabilkan lebih banyak opsi.

Sayangnya "kebersihan 100% penuh" masih bertahun-tahun lagi, dan tujuan proposal ini adalah untuk mendapatkan sesuatu yang stabil untuk Rust 2018

@alexcrichton Jadi, apakah rencana untuk menstabilkannya sekarang dengan lubang kebersihan dan kemudian beberapa zaman/era/edisi kemudian memperbaiki lubang kebersihan itu?

Sejak Span::call_site() ada, apakah ada alasan mengapa tidak dapat memiliki kebersihan penuh sekarang? Apakah kekurangan tenaga/waktu, atau apakah ada masalah teoretis/semantik yang masih perlu disempurnakan dalam RFC?

@Pauan untuk menegaskan kembali tidak ada "lubang" nyata dalam arti bahwa itu sudah ada hari ini. Ini adalah kisah kebersihan yang sama persis dengan macro_rules! dan turunan kustom. Proposal ini secara efektif merupakan perpanjangan dari itu, bukan memperkenalkan sesuatu yang baru.

Mengingat "kisah kebersihan yang sempurna" kami akan selalu menginginkan beberapa bentuk opt-out. Saat ini opt-out adalah Span::call_site() (efektif). Dengan hanya menstabilkan bahwa kami hanya menstabilkan mekanisme opt-out untuk kebersihan. Pada akhirnya kami akan menstabilkan lebih banyak fungsi untuk membuat barang sepenuhnya higienis jika diperlukan.

Menstabilkan kebersihan jauh lebih jauh. Ada (AFAIK) pertanyaan penelitian yang belum terselesaikan, ini bukan masalah tenaga kerja.

@dtolnay Ah, begitu. Jadi, Anda membuat teks dan kemudian mengurai ulang teks? Saya kira itu berhasil untuk saat ini.

cc @rust-lang/compiler, kalian semua yang saya tahu juga sangat tertarik dengan ini dan jangan ragu untuk mengajukan keberatan. Jika Anda memiliki keberatan pemblokiran, saya juga dapat mendaftarkannya untuk Anda

Saya masih memiliki beberapa hal untuk ditinjau dan PR dengan beberapa tweak proc-makro API sedang berlangsung.

Ini adalah kisah kebersihan yang sama persis dengan macro_rules! dan adat berasal.

Tentu, tapi saya pikir salah satu tujuannya adalah untuk membuat sistem makro yang lebih baik , jadi menunjuk ke sistem yang ada (rusak dan terbatas) tidak terdengar terlalu meyakinkan bagi saya.

Mengingat "kisah kebersihan yang sempurna" kami akan selalu menginginkan beberapa bentuk opt-out.

Benar-benar, tapi poin saya adalah bahwa karena itu mungkin untuk menggunakan Span::call_site() untuk istirahat kebersihan (dan dengan demikian mendapatkan macro_rules! fungsi) jika diinginkan, dengan membuatnya higienis secara default Anda mendapatkan akses ke kedua kebersihan dan tidak higienis. Sedangkan jika stabil dengan non-higienis maka terjebak hanya dengan non-higienis.

Pada akhirnya kami akan menstabilkan lebih banyak fungsi untuk membuat barang sepenuhnya higienis jika diperlukan.

Kedengarannya seperti bantuan pita yang agak mengganggu (dan membingungkan): makro proc akan higienis di sebagian besar situasi (tetapi bukan item), tetapi Anda kemudian dapat menggunakan fitur baru untuk memilih kebersihan untuk item. Apakah saya memahaminya dengan benar?

Ada (AFAIK) pertanyaan penelitian yang belum terselesaikan, ini bukan masalah tenaga kerja.

Oke, itu cukup adil. Saya memahami keinginan untuk kemanfaatan dan pragmatisme. Selama rencananya adalah untuk akhirnya memiliki kebersihan yang solid secara default di zaman/era/edisi selanjutnya, maka saya baik-baik saja untuk sementara memiliki kebersihan yang buruk. Aku hanya tidak ingin kita menstabilkan sesuatu yang akan kita sesali nanti.

Dalam arti, itu sudah merupakan "higienis secara default," hanya saja default belum didukung. Span::call_site adalah pilihan keluar. :)

@Pauan Untuk menguraikan apa yang @alexcrichton katakan:

Membangun pengenal memerlukan Span , yang berisi informasi kebersihan. (Lihat Term::new )

Di masa mendatang, kami mungkin mengungkap banyak cara berbeda untuk menyusun Span s, yang mencerminkan opsi berbeda untuk kebersihan. Tetapi untuk saat ini, kami hanya akan mengekspos Span::call_site yang mengambil ruang lingkup pemanggil.

Dengan cara ini, kita dapat menghindari menstabilkan seluruh sistem kebersihan segera, sambil tetap membuka kemampuan untuk menambahkan kebersihan nanti. Saya pikir itu trik yang cukup pintar untuk mengatasi masalah ini!

@rpjohnst Jadi maksud Anda satu-satunya cara untuk mengembalikan item baru dari makro proc adalah dengan menggunakan Span::call_site ?

Jika demikian, maka itu terdengar sempurna: dalam hal ini kebersihan memang dapat ditambahkan di masa depan dengan cara yang bersih dan kompatibel.

@lfairy Ahhh, begitu, saya tidak menyadari bahwa perlu menggunakan Span::call_site , saya pikir ada cakupan tidak higienis default implisit. Terima kasih atas penjelasannya! Anda benar itu adalah trik yang sangat pintar.

Karena itu, saya tidak memiliki keberatan lagi.

@alexcrichton

Atribut, macro_rules, dan prosedural
makro semua berada di namespace maro.

Terakhir saya memeriksa #[feature(proc_macro)] , ada perubahan yang tidak kompatibel ke belakang dalam kode stabil untuk peti rantai turunan sini. Dari pernyataan yang dikutip, sepertinya akan terus seperti ini di makro 1.2. Apakah itu benar?

@Arnavion oh sayang, itu terdengar buruk! Kami benar-benar tidak dapat melakukan perubahan besar yang tidak kompatibel ke belakang, jadi kami harus mencari cara untuk membuatnya tetap berfungsi. Salah satu solusi yang mungkin adalah menunda kesalahan "ini bukan atribut" hingga setelah #[derive] ekspansi.

Tampaknya #48644 dan #47786 sudah selesai. Bisakah seseorang memperbarui OP?

@alexcrichton Apakah ada diskusi tentang mengizinkan akses ke data internal Literal dan teman-teman? Saya mengerti bahwa mereka bukan enum lagi karena alasan kompatibilitas mundur tetapi apakah ada alasan mengapa kami tidak dapat memiliki sesuatu seperti ini untuk Literal untuk memulai:

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

Kami bahkan dapat memiliki banyak impls TryFrom untuk subtipe literal yang berbeda.

@abonander sudah dibahas ya tapi kesimpulannya adalah menambahkannya nanti daripada membuatnya diperlukan untuk stabilisasi pertama. Mereka dapat dibangun di crates.io dengan implementasi Display dan kami memiliki ruang untuk menambahkannya nanti di masa mendatang

:bell: Ini sekarang memasuki periode komentar terakhir , sesuai ulasan di atas . :lonceng:

@alexcrichton
!Send dan !Sync impls untuk jenis API makro proc tidak ditulis secara eksplisit, tetapi disimpulkan.
Untuk beberapa struct (misalnya Op ) impl yang disimpulkan berbeda dari apa yang ditentukan dalam https://github.com/rust-lang/rust/issues/38356#issuecomment -383693017.
Mungkin masuk akal untuk menambahkan impls secara eksplisit.

Ups ya memang! Saya telah membuka https://github.com/rust-lang/rust/pull/50453 untuk mengatasinya

@alexcrichton Kami memiliki masalah buruk dengan Term::as_str : Saya mencoba membuat sketsa bukti informal bahwa karena pelingkupan yang ketat, &'a Term -> &'a str dapat diimplementasikan untuk meminjam ke beberapa interner yang dicakup, dan 'a tidak pernah bisa lebih besar dari ruang lingkup interner itu sendiri (yang hanya penting jika fungsi berhasil, yaitu jika dipanggil dalam lingkup yang interner tinggal selama).

AFAICT, Term::as_str adalah suara , tetapi hanya dengan asumsi bahwa 'a kondisi.

Yang didukung oleh misalnya thread_local! , karena, sementara itu memungkinkan Anda melarikan diri dari nilai Term , itu memberi Anda 'a s yang sangat singkat, yang jika Term::as_str berhasil, benar-benar lebih pendek dari lingkup internal.
Secara umum, cara proc_macro ekspansi terjadi, dan karena Term adalah thread-local, hanya ada sedikit cara untuk keluar dari Term , dan saya berasumsi thread_local! secara efektif adalah satu-satunya.

Tapi Box::leak juga ada! Itu masih tidak stabil, tetapi hari ini, Box::leak(Box::new(term)).as_str() mengembalikan &'static str . Saya ingin tahu apakah ada abstraksi lain yang rusak oleh Box::leak (cc @RalfJung)

OTOH, ini hanya rumit karena Term tidak dapat memiliki data string, karena Copy .
Jika kita menghapus Copy pada Term , kita bisa menyimpan Option<Cell<Rc<String>> malas di sana.

@eddyb oh Term::as_str dijadwalkan untuk dihapus dan tidak disertakan dalam stabilisasi di sini, jadi tidak perlu khawatir! Itu hanya bertahan sehingga kami tidak merusak proc-macro2 , tetapi setelah ini stabil, kami dapat merilis perubahan yang melanggar untuk proc-macro2

@eddyb Saya tidak tahu konteksnya di sini, tetapi Box::leak dibenarkan dalam model formal saya. Jika Anda memiliki beberapa memori selamanya (yaitu, di dalam kotak), Anda benar-benar dapat mengatakan bahwa memori itu memiliki masa hidup apa pun.

Saya punya beberapa pertanyaan:

  1. Apakah quote! tidak stabil?
  2. Apakah quote! akan menerapkan gerbang fitur proc_macro_non_items ? Komit 79630d4fdfc775b241cae0a209edec2687a29f0f sekarang membutuhkannya, tetapi quote! masih ditandai #[unstable(feature = "proc_macro" ... .
  3. Apakah masalah pelacakan akan diajukan untuk stabilisasi proc_macro_path_invoc , proc_macro_mod , proc_macro_expr , dan proc_macro_non_items ?

Pertanyaan sampingan yang tidak terkait: di mana quote! diimplementasikan?

@mjbshaw Sooo cerita menyenangkan: ini diterapkan dalam proc_macro::quote .
rustc_metadata berpura-pura bahwa setiap peti bernama proc_macro berisi makro prosedural bernama quote di dalamnya, tetapi implementasi yang digunakan adalah dari proc_macro rustc_metadata link melawan.

Saya masih memiliki beberapa hal untuk ditinjau dan PR dengan beberapa tweak proc-makro API sedang berlangsung.

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

Permintaan fitur untuk 1.2 API: tambahkan pembatas untuk kurung sudut ( < / > ) sehingga hal-hal seperti <T> (dalam fn foo<T>() {} ) akan diuraikan sebagai sebuah Group . Tidak melakukan ini membuat penguraian misalnya obat generik menjadi tidak perlu rumit.

@mjbshaw Saya tidak berpikir itu akan berhasil pada tingkat token untuk mencoba menentukan apakah dua < > dikelompokkan satu sama lain. Misalnya pada input makro berikut:

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

Mungkin ini adalah dua ekspresi boolean $A < $B dan $C >= $D , atau mungkin mewakili generik dalam tipe alias misalnya berkembang menjadi type $A <$B,$C> = $D; .

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

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

Saya telah memperbarui OP sedikit, tetapi kami memiliki apa yang tampak seperti dua bug showstopper yang mungkin terkait dengan kebersihan, tergantung pada bagaimana hasilnya:

Bagi mereka yang mengikuti utas ini, API kemungkinan akan diubah dari komentar FCP asli di https://github.com/rust-lang/rust/pull/50473 yang diusulkan oleh @petrochenkov. Ringkasan sejauh ini adalah:

  • Ganti nama Term::new menjadi Term::ident dan validasi input
  • Tambahkan Term::lifetime dan validasi input
  • Tambahkan Term::raw_ident dan validasi input
  • Ganti nama Op menjadi Punct
  • Validasi masukan pada Punct::new
  • Ganti nama Op::op menjadi Punct::as_char

Satu permintaan API kecil yang akan saya buat (mungkin di #50473 -- @petrochenkov) adalah beberapa cara untuk menambahkan token ke TokenStream. Mungkin:

impl Extend<TokenTree> for TokenStream

Saya percaya ini akan memungkinkan untuk menghilangkan jenis quote::Tokens (yang pada dasarnya adalah Vec<TokenTree> ) dan mengurangi proliferasi berbagai jenis dalam ekosistem yang semuanya berarti "beberapa token" -- dilacak di https ://github.com/dtolnay/syn/issues/205.

+1 pada saran @dtolnay di atas.

Periode komentar terakhir, dengan kecenderungan untuk menggabungkan , sesuai ulasan di atas , sekarang selesai .

Saya punya dua pertanyaan:

  1. Seperti yang sudah ditanyakan di sini , ada apa dengan quote! ? Apa yang seharusnya menjadi cara default untuk membuat TokenStream final? Apakah harus dilakukan secara manual? Atau haruskah seseorang menggunakan peti quote ? Apakah proc_macro::quote! seharusnya stabil di beberapa titik di masa depan?

  2. Apakah pemahaman saya benar karena perbedaan antara mendeklarasikan makro seperti fungsi dan makro seperti atribut hanyalah jumlah argumen? Yaitu:

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

    Satu-satunya perbedaan adalah bahwa yang satu mengambil satu TokenStream sebagai argumen, di mana yang lain mengambil dua . Bukankah ini agak halus? Mengapa tidak menggunakan #[proc_macro_attribute] dan #[proc_macro_function_like] saja? Apakah ini pernah dibahas di suatu tempat? Jika demikian, saya akan senang jika seseorang dapat menghubungkan diskusi tersebut.

Terima kasih atas pekerjaan Anda dalam hal ini! :)

@LukasKalbertodt Atribut saat ini dideklarasikan dengan #[proc_macro_attribute] . Saya tidak tahu apakah ada niat yang disengaja untuk mengubahnya atau apakah itu salah ketik dalam proposal FCP.

Masalah: Token yang diurai dari string tidak mendapatkan rentang Span::call_site : https://github.com/rust-lang/rust/issues/50050#issuecomment -390520317.

Saya pikir kita perlu mengubah ini dan juga mengubah apa yang Span::call_site kembalikan untuk memperbaiki backtrace makro, clippy, dan kebersihan edisi untuk token menggunakan rentang situs panggilan.

@LukasKalbertodt quote! makro dalam peti proc_macro tidak distabilkan sebagai bagian dari FCP ini, tetapi peti quote pada crates.io dibangun di atas API yang diusulkan di sini. Juga seperti yang ditunjukkan @abonander, makro atribut dideklarasikan dengan #[proc_macro_attribute] dan #[proc_macro] dicadangkan secara eksklusif untuk foo!() -gaya makro

Bukankah seharusnya #[proc_macro_attribute] diberi nama #[proc_attribute_macro] atau #[attribute_proc_macro] ?

@Zoxc Kami sudah memiliki #[proc_macro_derive] stabil, jadi akan aneh untuk tidak mengikutinya untuk atribut makro.

Bisakah kita mendapatkan PartialEq<char> dan PartialEq<Punct> untuk Punct (mirip dengan Ident 's PartialEq implementasi)? Sepertinya itu harus cukup aman untuk ditambahkan. Saya senang menulis PR, tetapi tidak mau jika idenya tidak boleh.

@mjbshaw Apakah PartialEq<Punct> juga akan membandingkan rentang? PartialEq<char> sepertinya baik-baik saja, OTOH.

@eddyb PartialEq untuk Ident tidak membandingkan rentang (saya tahu ini adalah sumber proc-macro2 dan bukan sumber proc-macro). Saya ragu apakah rentang disertakan dalam perbandingan, tetapi saya berharap Punct dan Ident berperilaku serupa dalam hal ini. Punct juga memiliki Spacing , yang saya kira akan dimasukkan dalam perbandingan (meskipun mungkin orang lain berpikir berbeda).

Saya akan baik-baik saja hanya menerapkan PartialEq<char> untuk Punct untuk saat ini. PartialEq<Punct> dapat di-hash nanti.

@mjbshaw peti proc-macro2 memiliki kebebasan untuk tidak persis seperti proc_macro upstream dan memberi kita kebebasan untuk bereksperimen dengan berbagai tweak. Saya menduga bahwa jika berhasil dengan baik di crates.io, kita dapat menambahkannya ke proc_macro , tetapi tentu saja kompatibel ke belakang untuk ditambahkan ke proc_macro jadi kita mulai dengan minimum dan kita dapat meningkatkan dari sana setelah stabil.

Saya telah melakukan beberapa pekerjaan triase untuk semua bug yang terkait dengan makro 1.2 . Sebagian besar bug dapat diklasifikasikan ke dalam "bug serius" atau "bug terkait semua rentang". Saat ini bug terkait rentang murni memengaruhi pesan kesalahan (karena maksud makro 1.2 bukan untuk mengubah resolusi). Bug terkait non-rentang yang tersisa (alias serius) adalah https://github.com/rust-lang/rust/issues/50050 , yang @petrochenkov memiliki solusi untuk .

Kelas Gnome pecah dengan perubahan ke proc_macro2/syn/quote, ditambah gerbang fitur untuk menghasilkan modul dari makro proc. Sekarang sudah diperbaiki, untungnya.

Hal-hal apa yang harus saya pantau untuk terus mengikuti perubahan dalam ekosistem kecil ini?

@federicomenaquintero Jika Anda menggunakan fitur yang tidak stabil, pertimbangkan untuk memiliki pekerjaan CI reguler (harian, mingguan, apa pun yang sesuai untuk Anda) yang mengkompilasi kode Anda dengan Nightly terbaru dan memberi tahu Anda jika gagal. (Travis-CI mendukung pengaktifan "cron job" dalam pengaturannya.)

@SimonSapin terima kasih, itu ide yang bagus. Kami menyematkan versi peti-peti itu di Cargo.toml kami, tetapi mungkin sudah waktunya untuk menghapus nomor versi dan membiarkan Cargo mengunduh yang terbaru. Apakah ini cara yang benar untuk melakukannya?

@federicomenaquintero Ini semakin di luar topik jadi jika Anda ingin melanjutkan diskusi ini, silakan lakukan di tempat lain seperti di IRC atau http://users.rust-lang.org/ , tetapi rekomendasi umumnya adalah aplikasi itu (sebagai bertentangan dengan perpustakaan) harus mengirimkan Cargo.lock bersama dengan kode sumbernya, yang secara efektif menyematkan dependensi. Dalam Cargo.toml , mendeklarasikan ketergantungan seperti foo = "1.2.3" direkomendasikan, itu secara implisit berarti "versi itu atau yang lebih baru, jika kompatibel menurut SemVer".

Jadi, saya baru saja mengalami masalah dengan makro prosedural yang menghalangi saya dalam mengembangkan peti yang ingin saya buat.

Pertimbangkan hal berikut:

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

Saat ini tidak berfungsi karena kedua fitur proc_macro dan custom_attributes diperlukan tetapi tidak dapat digunakan secara bersamaan. Seperti yang saya pahami, stabilisasi makro proc akan menghilangkan kebutuhan akan tanda fitur?

Hal lain adalah bahwa cara ini #[my_attribute] berpotensi menghasilkan kode yang mencegah #[other_attribute] dijalankan. Apa yang akan sangat keren jika pada atribut "luar", saya dapat mendaftarkan atribut dalam yang bekerja dengan cara yang sama seperti #[derive(Foo)] bekerja.

Bagaimana dengan komentar @SimonSapin tentang sesi dummy ?

Apakah mungkin/diinginkan untuk mengganti kepanikan ini dengan secara implisit membuat "sesi" dummy? Atau mungkin menambahkan API publik (dengan jalur menuju stabilisasi) untuk membuatnya?

Saya pikir akan sangat berguna untuk memiliki sesi dummy. Menulis unit test untuk peti proc-macro hampir tidak mungkin atau setidaknya sangat merepotkan. Selain itu, tidak hanya TokenStream::from_str , tetapi juga fungsi lain yang membutuhkan sesi.

@alexcrichton

Saya telah melakukan beberapa pekerjaan triase untuk semua bug yang terkait dengan makro 1.2. Sebagian besar bug dapat diklasifikasikan ke dalam "bug serius" atau "bug terkait semua rentang".

Saya ingin memutakhirkan https://github.com/rust-lang/rust/issues/50504 ke status "serius" - masalah modul yang dijelaskan hanya ada gejala masalah yang lebih dalam - ID ekspansi untuk makro proc tidak sedang didaftarkan dengan benar. Saya tidak tahu apa konsekuensi lain dari ini.
Ada PR yang memperbaiki masalah mendasar ( https://github.com/rust-lang/rust/pull/51952 ), tetapi ada regresi dari perbaikan dan saya belum memeriksanya.

Saya telah memposting PR untuk menstabilkan lebih banyak makro prosedural di https://github.com/rust-lang/rust/pull/52081

@petrochenkov terdengar bagus untuk saya, saya akan mengomentari PR

Saya baru saja memposting masalah pelacakan penamaan makro tentang masalah dengan atribut anak proc_macro_derive dan bagaimana mereka berinteraksi dengan sistem penamaan. Ada masalah lain dengan cara atribut anak proc_macro_derive berinteraksi dengan pelingkupan dan penamaan, tetapi tampaknya lebih relevan untuk diangkat di sini. Karena jalur dalam atribut saat ini tidak menuju stabilisasi, kami mendapatkan kemungkinan bahwa #[derive(foo::Parent)] dapat memiliki atribut anak #[foo::Child] , tetapi makro derivasi tidak akan memiliki cara, di wajahnya, untuk mengidentifikasi apakah atribut anak sebenarnya adalah anaknya sendiri, karena tidak dapat melakukan pencarian nama. Untuk saat ini, saya tidak memiliki solusi yang mudah, tetapi saya pikir itu adalah sesuatu yang harus ada di radar untuk masa depan atribut yang saling bergantung; tidak ada alasan bahwa atribut proc_macro_attribute tidak ingin berinteraksi dengan cara yang mengalami masalah pencarian serupa.

Saya mencoba mengkompilasi proyek saya hari ini, tetapi ada sesuatu yang rusak yang mungkin terkait dengan masalah ini. Semua pesan kesalahan memiliki pesan: "(lihat masalah #38356)". Ini adalah bagaimana saya sampai di sini.
Saya menyertakan di sini pesan kesalahan yang saya dapatkan selama kompilasi. Saya juga menyertakan Cargo.toml saya.

Saya menemukan ini sangat mengejutkan, karena proyek saya disematkan ke versi Rust nightly tertentu (rustc 1.29.0-nightly (9bd8458c9 2018-07-09)) Apa yang bisa berubah? Mungkin perpustakaan diperbarui?

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

Kesalahan kompilasi

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

Apakah Anda memiliki gagasan tentang apa yang mungkin salah, dan bagaimana cara memperbaikinya? Terima kasih!

@realcr untuk proc-macro2 Anda cukup menjalankan cargo update dan itu akan berhasil!

@alexcrichton Saya tidak berpikir itu masalahnya di sini. Saya lebih suka @realcr sudah memperbarui proc-macro2 karena pesan kesalahan mengatakan proc-macro2-0.4.8 mana-mana. Masalahnya adalah bahwa versi malamnya diperbaiki ke versi yang tidak menyertakan #52081. Saya memiliki masalah yang sama hari ini dan bertanya-tanya mengapa proc-macro2 hanya menabrak versi minor. Tapi saya tidak terlalu paham bagaimana proc-macro2 menangani kompatibilitas.

@realcr Coba perbarui kompiler malam Anda atau terapkan versi proc-macro-2 < 0.4.8 di proyek Anda.

@alexcrichton , @LukasKalbertodt : Terima kasih atas balasan cepatnya.
Saya baru saja memperbarui kompiler malam saya ke versi terbaru. Itu menghilangkan masalah proc-makro-2, tetapi saya mendapat banyak kesalahan kompilasi baru. Contoh:

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)

Untuk mengonfirmasi, versi rustc saya saat ini:

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

Untuk melacak sumber masalah, saya mencoba mengkompilasi contoh dasar dari futures_await tetapi berhenti bekerja juga. Saya akan mengajukan masalah di sana sehingga kami dapat menyelesaikan masalah ini.

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

Karena Anda menggunakan fitur yang tidak stabil.

@realcr masalah kompilasi baru Anda tidak terkait dengan masalah ini, harap tetap pada topik.

@TeXitoi : Jangan ragu untuk mengedit atau menghapus apa pun jika menurut Anda itu tidak relevan. Saya mencoba yang terbaik untuk membantu Anda, sulit bagi saya untuk mengetahui apa yang ada di topik dan apa yang tidak. Pesan kesalahan "(lihat masalah #38356)" adalah yang membawa saya ke sini.

Saya mencoba memutakhirkan versi kompiler saya dan saya mendapatkan kesalahan ini. kode saya

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

#[macro_use(eth_abi)]
extern crate pwasm_abi_derive;

dan kesalahan yang mengatakan bahwa saya tidak menggunakan #![feature(proc_macro)] , tetapi saya melakukannya!

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 Anda ingin mengganti #![feature(proc_macro)] ke #![feature(use_extern_macros)] dan itu akan berhasil

Saya pikir Anda juga harus menggunakan sistem modul untuk mengimpor makro prosedural (dan pastikan Anda memiliki kompiler malam terbaru)

@alexcrichton ya, saya baru tahu, berkat artikelnya . Namun, itu masih tidak berfungsi:

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

Aturan impor untuk makro telah berubah juga? Atau saya tidak tahu mengapa itu mulai mengeluh di sini.

@Pzixel yang mungkin merupakan bug di makro prosedural atau kompiler, dapatkah Anda mengajukan masalah khusus untuk itu?

Yah, saya pikir saya harus menulis ulang kode saya terlebih dahulu untuk membuatnya setidaknya terlihat berfungsi :) Saat ini tidak, kalian banyak berubah dengan fitur ini. BRB setelah selesai. Jika tidak hilang saya membuat masalah.

@alexcrichton
Tahukah Anda apa "pemrosesan awal" yang diterapkan pada token sebelum diteruskan ke makro prosedural?
Saya tahu bahwa turunan memiliki setidaknya $crate dihilangkan dan cfg diperluas sebelum mereka mendapatkan token input (ditambah pulang pergi melalui string tidak sepenuhnya lossless, tapi itu bisa diperbaiki).

Kami harus memastikan semua ini tidak terjadi dengan makro prosedural yang baru distabilkan dan mereka mendapatkan token input dengan tepat (bug modulo).

@alexcrichton maaf, cargo expand tidak berfungsi di peti ini karena alasan tertentu. Tidak dapat mengonfirmasi apakah masalah ada di pihak saya atau di kompiler. Jadi saya akan terus menyalahkan diri sendiri sampai kemungkinan ini tidak sepenuhnya dikecualikan.

@petrochenkov perluasan proc-makro telah diperiksa dengan cukup baik hingga saat ini, jadi saya jauh lebih tidak khawatir tentang itu daripada potongan resolusi nama. Saya pribadi tidak mengetahui preprocessing, tetapi saya tahu bahwa ada urutan ekspansi di mana turunan dijalankan terakhir, cfgs dijalankan terlebih dahulu, dan selain itu sebagian besar iteratif.

Saya setuju meskipun itu bagus untuk diaudit!

Mungkin saya melewatkan sesuatu yang jelas. Tapi, apakah tidak ada cara untuk memanggil fungsi, menggunakan tipe, dll. dari peti pendefinisi proc_macro dari ekspansi makro prosedural? (atau peti lain yang diketahui dari peti proc_macro, FWIW)

Ada solusi , tetapi AFAIU tidak akan berfungsi jika peti diganti namanya oleh pengguna makro prosedural.

@Ekleog proc-macro peti biasanya hanya dikompilasi untuk tujuan membangun peti yang menggunakannya. Mereka bukan dependensi runtime. Anda dapat menganggap seluruh peti proc-makro sebagai semacam plugin kompiler, bukan perpustakaan "normal".

Ini terutama terlihat saat kompilasi silang: seperti skrip build, proc-makro dikompilasi untuk platform host, bukan platform target.

@SimonSapin Saya setuju dengan Anda, tetapi mungkin sangat berguna untuk mendelegasikan sebagian pekerjaan ke fungsi yang disediakan oleh peti, meskipun itu bukan peti proc-makro (mis. di tautan saya di atas, X-derive peti mencoba menggunakan fungsi dari peti X ). Karena jika tidak, itu berarti bahwa semua kode yang dihasilkan oleh proc-makro harus mandiri atau membuat asumsi tentang status situs panggilan.

Kemudian, saya dapat memahami bahwa rustc belum siap untuk fitur semacam ini (karena saya kira itu akan bekerja paling baik tanpa perlu memisahkan proc-makro dari peti non-proc-makro, yang tampaknya berada di suatu tempat di lama- istilah peta jalan). Tapi saya ingin tahu, jika antarmuka saat ini yang hanya menggunakan TokenStreams distabilkan, apakah mungkin untuk memperbaiki fitur ini nanti? Bukankah itu membutuhkan sesuatu seperti jenis token PathToBeResolvedFromTopOfGeneratingProcMacroCrate ? (yang akan menjadi perubahan besar jika ditambahkan nanti, afaiu)

Mungkin akan memungkinkan untuk membuat segalanya lebih fleksibel pada akhirnya, tetapi itu tampaknya cukup jauh.

Sementara itu, jika Anda seorang penulis pustaka, pertimbangkan untuk memiliki peti foo-proc-macros atau foo-derive untuk makro prosedural, dan pustaka foo "normal" yang berisi run-time kode tetapi juga mengekspor ulang makro prosedural. Dengan begitu, API yang dihadapi pengguna dapat disimpan ke dalam satu peti. Inilah yang dilakukan serde (dalam beberapa konfigurasi) https://github.com/serde-rs/serde/blob/v1.0.71/serde/src/lib.rs#L304

Perlu ditunjukkan bahwa solusi ini masih tidak mengatasi masalah pengguna yang mengganti nama root crate (misalnya masalah pelacakan serde ).

@Ekleog , TokenStream adalah aliran TokenTree s dan setiap TokenTree telah dikaitkan Span , yang membawa informasi pelingkupan. Kecuali saat ini tidak ada cara untuk membuat Span untuk cakupan selain "situs panggilan" (atau kosong). Pada dasarnya datang dengan cara yang cukup ergonomis untuk membuat Span merujuk ke peti tertentu adalah apa yang dibutuhkan.

Alasan saya bertanya adalah bahwa kotak centang tidak dicentang. Akan menyenangkan untuk menandainya saat itu!

Dengan #![feature(proc_macro)] stabil, apa yang tersisa dari masalah ini?

@jan-hudec Oh, saya pikir Span s hanya untuk pelaporan kesalahan, karena posting blog awal menyebutkan struct Hygiene (atau dengan nama serupa) yang memainkan peran ini. Saya berasumsi bahwa ini telah lenyap, dan ternyata salah. Terima kasih! :)

Dengan #![feature(proc_macro)] stabil, apa yang tersisa dari masalah ini?

Idealnya, masalah baru perlu diajukan untuk semua masalah yang tersisa dan bukan fitur yang distabilkan, dan kemudian masalah ini dapat ditutup (dengan cara yang sama seperti yang dilakukan untuk https://github.com/rust-lang/rust/issues/ 44660).

Oh, saya pikir Span hanya untuk pelaporan kesalahan, karena posting blog awal menyebutkan struct Hygiene (atau dengan nama serupa) yang memainkan peran ini. Saya berasumsi bahwa ini telah lenyap, dan ternyata salah. Terima kasih! :)

IIUC, Spans adalah cara utama untuk melacak konteks kebersihan.

@mark-im Jenis. Mereka mencakup informasi lokasi kode sumber (untuk pesan/diagnostik yang dilihat pengguna) dan konteks sintaks (yaitu informasi kebersihan).

Mengingat banyaknya diskusi/lalu lintas yang didapat masalah ini, apakah masuk akal untuk memindahkan proc_macro_diagnostic ke masalah pelacakannya sendiri? Saya juga ingin mencari tahu apa pemblokir untuk stabilisasi fitur itu, dan melihat apakah kami dapat mendorongnya. Diesel menggunakannya, dan sejauh ini sangat bagus. Kurangnya fitur ini di stable menyebabkan komunitas membuat solusi yang funky, seperti versi terbaru syn menggunakan compile_error! sebagai gantinya.

@sgrif Saya telah membuka masalah seperti itu: https://github.com/rust-lang/rust/issues/54140.

Jadi saya tertarik untuk membantu menstabilkan metode di Span dan struct LineColumn. Saya akan melihat masalah terbuka di komentar pertama, tetapi jika ada yang ingin mengarahkan pemula ke kompiler ke arah tertentu, saya akan menghargainya :+1:

Gerbang fitur proc_macro_gen mengarahkan saya ke sini, tetapi dalam daftar periksa di atas saya tidak melihat apa pun yang jelas-jelas merujuk ke makro (proc_) yang menghasilkan definisi makro lainnya. Apakah ini telah diperhitungkan (selain di gerbang fitur rustc)?

@jjpe mungkin saat ini yang terbaik adalah kami memisahkan masalah pelacakan khusus untuk gerbang fitur tersebut, masalah ini sebagian besar didedikasikan untuk gelombang awal stabilisasi

@alexcrichton Saya baik-baik saja dengan itu, lebih dari itu dalam proses melihat fitur proc_macro_gen , itu merujuk saya ke sini hanya untuk menemukan yang terbaik tanpa menyebutkannya. Itu agak aneh bagi saya, jadi saya memutuskan untuk menyebutkannya, setidaknya.

@xieyuheng Seperti apa CodeString / Code terlihat seperti apa semantiknya?
Ingatlah bahwa TokenStream tidak lebih dari kode sumber kata demi kata kecuali sebagai serangkaian nilai token daripada teks yang mengganggu.

API yang diperluas untuk TokenStream (dengan TokenTree ) stabil di 1.29. Mengimpor makro proc seperti fungsi akan stabil di 1,30.

Tampaknya sejak rustc 1.30.0-nightly (63d51e89a 2018-09-28) tidak mungkin lagi melintasi kode di dalam modul dalam file terpisah. Jika Anda memproses mod module; , Anda mendapatkan TokenStream berisi mod module; , WYSIWYG.

Saya mengerti, bahwa ini diperlukan untuk menjaga rentang, kebersihan, dan konsistensi dengan kode yang diproses. Apakah ada atau akan ada cara untuk bekerja dengan konten modul dalam file terpisah? Kekurangannya mungkin membingungkan pengguna akhir ketika refactoring sepele dari organisasi modul menyebabkan perubahan perilaku makro.

Oke masalah ini sangat besar dan sampai pada titik yang menurut saya tidak terlalu berguna untuk tetap membuka dan melacak API. Untuk itu saya telah membuka https://github.com/rust-lang/rust/pull/54728 yang membagi masalah ini menjadi beberapa masalah pelacakan yang lebih halus:

Pada titik ini saya akan menutup ini, tetapi jika saya lupa memisahkan masalah pelacakan lainnya, beri tahu saya! Saya pasti bisa membuka beberapa tindak lanjut

@alexcrichton Bagaimana dengan sub-atribut untuk makro seperti atribut?
https://github.com/rust-lang/rust/issues/38356#issuecomment -397095541
Apakah ada masalah untuk ini?

@XX
Sub-atribut seperti itu tidak harus berupa fitur bahasa?
Dalam hal derive pendaftaran atribut khusus diperlukan karena makro turunan tidak dapat menghapus atribut dari inputnya (inputnya tidak dapat diubah).
Makro atribut dapat menghapus #[other_attribute] s dari inputnya, sehingga makro atribut tidak akan pernah mendapatkan resolusi nama dan tidak pernah melaporkan kesalahan "atribut yang belum terselesaikan".

(Selain itu, atribut kustom warisan klasik yang tidak stabil yang disebutkan di https://github.com/rust-lang/rust/issues/38356#issuecomment-397095541 sekarang kompatibel dengan makro proc.)

@petrochenkov Ya, terima kasih atas klarifikasinya.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat