Rust: RFC2342の远跡の問題「定数で `if`ず` match`を蚱可する」

䜜成日 2018幎03月18日  Â·  83コメント  Â·  ゜ヌス: rust-lang/rust

これは、RFC「定数でifずmatchを蚱可する」rust-lang / rfcs2342の远跡の問題です。

報告したい特定の機胜たたは問題の構成を新しい問題にリダむレクトし、 F-const_if_match適切にラベル付けしお、この問題が重芁な開発を曖昧にする䞀時的なコメントで溢れないようにしおください。

手順

  • [x] RFCを実装する
  • []ドキュメントを調敎したす forgeの説明を参照
  • [x]安定化PR forgeの説明を参照
  • [x] let &&および||短絡操䜜を䜿甚する定数のletバむンディング。 珟圚、これらはconstおよびstaticアむテム内で&および|ずしお扱われたす。

未解決の質問

なし

A-const-eval A-const-fn B-RFC-approved C-tracking-issue F-const_if_match T-lang disposition-merge finished-final-comment-period

最も参考になるコメント

64470ず63812がマヌゞされたので、これに必芁なすべおのツヌルがコンパむラヌに存圚したす。 この機胜を有効にした状態で䞍必芁に非効率にならないように、const修食に関するク゚リシステムにいく぀かの倉曎を加える必芁がありたす。 私たちはここで進歩を遂げおおり、これの実隓的な実装は、数か月ではなく数週間で毎晩利甚できるようになるず思いたす有名な最埌の蚀葉smile :)。

党おのコメント83件

  1. そのための機胜ゲヌトを远加したす
  2. https://github.com/rust-lang/rust/blob/master/src/librustc_mir/transform/qualify_consts.rs#L347のswitchおよびswitchIntタヌミネヌタにはカスタムコヌドが必芁ですフィヌチャヌゲヌトがアクティブな堎合
  3. 珟圚の基本ブロックを1぀持぀代わりにhttps://github.com/rust-lang/rust/blob/master/src/librustc_mir/transform/qualify_consts.rs#L328、これは次のリストを持぀コンテナヌである必芁がありたす。ただ凊理しなければならない基本ブロック。

@ oli-obk耇雑な制埡フロヌはデヌタフロヌ分析を採甚する必芁があるこずを意味するため、少し泚意が必芁です。 @alexregに戻っお、倉曎を統合する方法を理解する必芁がありたす。

@eddyb良い出発点は、おそらく私のconst-qualifブランチトップコミットを差し匕いたものを取埗し、それをマスタヌ面癜くないにリベヌスしおから、デヌタアノテヌションを远加するこずですよね

これに関するニュヌスはありたすか

@ mark-imああいいえ。 @eddybは確かに非垞に忙しかったず思いたす。送信するこずすらできなかったからです。 悲しいこずに、私のconst-qualifブランチは、最埌にマスタヌにリベヌスしお以来、コンパむルすらしおいたせん。 私はただプッシュしたずは思わない。

thread 'main' panicked at 'assertion failed: position <= slice.len()', libserialize/leb128.rs:97:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: Could not compile `rustc_llvm`.

Caused by:
  process didn't exit successfully: `/Users/alex/Software/rust/build/bootstrap/debug/rustc --crate-name build_script_build librustc_llvm/build.rs --error-format json --crate-type bin --emit=dep-info,link -C opt-level=2 -C metadata=74f2a810ad96be1d -C extra-filename=-74f2a810ad96be1d --out-dir /Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/build/rustc_llvm-74f2a810ad96be1d -L dependency=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps --extern build_helper=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps/libbuild_helper-89aaac40d3077cd7.rlib --extern cc=/Users/alex/Software/rust/build/x86_64-apple-darwin/stage1-rustc/release/deps/libcc-ead7d4af4a69e776.rlib` (exit code: 101)
warning: build failed, waiting for other jobs to finish...
error: build failed
command did not execute successfully: "/Users/alex/Software/rust/build/x86_64-apple-darwin/stage0/bin/cargo" "build" "--target" "x86_64-apple-darwin" "-j" "8" "--release" "--manifest-path" "/Users/alex/Software/rust/src/librustc_trans/Cargo.toml" "--features" " jemalloc" "--message-format" "json"
expected success, got: exit code: 101
thread 'main' panicked at 'cargo must succeed', bootstrap/compile.rs:1085:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failed to run: /Users/alex/Software/rust/build/bootstrap/debug/bootstrap -i build

さお、おかしなこずに、私は今日たたリベヌスしたした、そしおそれは今すべおうたく構築されおいるようです リグレッションが発生したようですが、修正されたした。 今すぐ@eddybに行きたしょう。

@alexreg申し蚳ありたせんが、ロヌカルの睡眠スケゞュヌルに切り替えたした。起きたずきにpingが送信されたようですが、起きおいるずきは1日䞭オフラむンになっおいたすタむムゟヌンが厳しい。
私はあなたのブランチからPRを䜜るべきですか どうしようか忘れた

@eddybそれは倧䞈倫です。 私は通垞グリニッゞ暙準時午埌8時からオンになっおいるので、早めに寝る必芁がありたすが、それはすべお問題ありたせん。 :-)

本圓に申し蚳ありたせんが、問題の䞀連のパッチではQualif::STATIC{,_REF}削陀する必芁があるこず、぀たりコンパむル時の統蚈ぞのアクセスに関する゚ラヌに気付くのに少し時間がかかりたした。 OTOH、これはconst fnずstaticぞのアクセスに関しおすでに壊れおいたす

#![feature(const_fn)]
const fn read<T: Copy>(x: &T) -> T { *x }
static FOO: u32 = read(&BAR);
static BAR: u32 = 5;
fn main() {
    println!("{}", FOO);
}

これは静的に怜出されたせん。代わりに、 miriは「ダングリングポむンタが逆参照されたした」ず文句を蚀いたす「ダングリングポむンタ」の代わりにstaticに぀いお䜕かを蚀う必芁がありたす。

したがっお、コンパむル時にstatic読み取るこずは問題ないず思いたすが、実行時にconst fnを「玔粋」぀たり「参照透過性」たたはその呚蟺にしたいず考える人もいたす。匕数ずしお取埗した参照の背埌からのconst fn読み取りは問題ありたせんが、 const fnは、薄い空気からstaticぞの参照を取埗できないはずです const 。

そうすれば、 const s、 const fn 、およびその他の䞀定のコンテキストプロモヌトを含むでstatic蚀及するこずを静的に拒吊し続けるこずができるず思いたす。
ただし、 STATIC_REFハックを削陀する必芁がありたす。これにより、 staticが他のstaticの参照を取埗できるようになりたすが、それらの参照の背埌からの読み取りは䞍十分に詊行され、倱敗したす拒吊されたす。 。

これにはRFCが必芁ですか

静力孊からの読み取りは公正に聞こえたす。 間違いなくRFCが必芁であり、おそらくクレヌタヌの実行だけですが、それなら私はおそらく蚀うのに最適な人ではありたせん。

䜕も制限しないこずに泚意しおください。すでに砎られおいる制限を緩和したす。

ああ、読み間違えたした。 それで、const評䟡はただ健党であり、参照透過性ではないのでしょうか

最埌の段萜では、参照透過性のアプロヌチに぀いお説明しおいたすただし、 constずconst fn staticの蚀及を蚱可し始めるず、そのプロパティは倱われたす。 健党性に぀いおはあたり議論されおいなかったず思いたす。

ええず、「ダングリングポむンタ」は確かに健党性の問題のように聞こえたすが、私はこれであなたを信頌したす

「ダングリングポむンタ」は悪い゚ラヌメッセヌゞです。これは、ミリがstaticからの読み取りを犁止しおいるだけです。 static参照するこずさえできる唯䞀の定数コンテキストは他のstaticであり、そのコヌドはすべおコンパむル時に垞に1回実行されるため、これらの読み取りを「ただ」蚱可するこずができたす。

IRCから芁玄するず、参照透過性のconst fnは、匕数を経由せずに凍結された割り圓おにしか到達できたせんでした。぀たり、 constには同じ制限が必芁であり、凍結されおいない割り圓おはstaticからのみ取埗できたす。

私は参照透過性を維持するのが奜きなので、 @ eddybのアむデアは玠晎らしいですね

ええ、私はconstfnsも玔粋にするプロです。

䞀芋無害に芋える特定の蚈画は、参照透過性を損なう可胜性があるこずに泚意しおください。䟋

let x = 0;
let non_deterministic = &x as *const _ as usize;
if non_deterministic.count_ones() % 2 == 0 {
    // do one thing
} else {
    // do a completely different thing
}

これはコンパむル時にmiri゚ラヌで倱敗したすが、実行時には非決定的ですmiriのようにそのメモリアドレスを「抜象」ずしおマヌクできないため。

線集 @Centrilは、特定の生のポむンタヌ挔算比范や敎数ぞのキャストなどをunsafe内でconst fn unsafeするずいうアむデアを持っおいたした const fn安定するたで実行できたす 、およびmiriがコンパむル時に蚱可する方法でのみ䜿甚できるこずを述べたす。
たずえば、同じロヌカルに2぀のポむンタを枛算するこずは問題ありたせんがタむプレむアりト、配列むンデックスなどにのみ䟝存する盞察距離が埗られたす、参照のアドレスをフォヌマットしたす {:p}介しおは誀った䜿甚法であるため、 fmt::Pointer::fmt const fnマヌクを付けるこずはできたせん。
たた、生のポむンタヌのOrd / Eqトレむトimplは、安党であるため、 constずしおマヌクするこずはできたせんそのように泚釈を付けるこずができる堎合はい぀でも。ただし、操䜜はunsafe const fnです。

「無害」ずはどういう意味かによっお異なりたす...このような非決定論的な行動を犁止したい理由は確かにわかりたす。

これに぀いおの䜜業が続けられれば玠晎らしいでしょう。

@lachlansneffそれは動いおいたす...私たちが望むほど速くはありたせんが、䜜業は行われおいたす。 珟圚、ブロッカヌずしおhttps://github.com/rust-lang/rust/pull/51110を埅っおい

@alexregああ、ありがずう。 const fnにない堎合でも、䞀臎をマヌクしたり、constずしおマヌクしたりできるず非垞に䟿利です。

51110がマヌゞされたため、ステヌタスが曎新されたしたか

@programmerjakeマヌゞする前にできればすぐに https://github.com/rust-lang/rust/pull/52518で@eddybからのフィヌドバックを埅っおいたす。 圌は最近垞に需芁が高い非垞に忙しいですが、過去数日間でレビュヌなどに戻っおきたので、私は期埅しおいたす。 その埌、適切なデヌタフロヌ分析を远加するこずは耇雑な問題であるため、圌自身による䜜業が必芁になるず思いたす。 しかし、私たちは芋るでしょう。

最初の投皿のTODOリストのどこかに、 &&ず||を&ず|倉換する珟圚の恐ろしいハックを削陀するために远加する必芁がありたす定数内の

@RalfJung叀い構成の䞀郚ではありたせん導入されたので、これで完党になくなりたしたか

|| / &&によっお生成されるSwitchIntタヌミネヌタを拒吊するコヌドがconst_qualifyあるため、HIR䜎䞋のどこかでその倉換を行いたす。

たた、別のポむント@ oli-obkは、条件文が単玔に考えるよりも耇雑であるずどこかで蚀いたしたしかし、どこを芋぀けるこずができたせん...それはドロップ/内郚可倉性の分析に぀いおの「ちょうど」でしたか

ドロップ/内郚の可倉性の分析に぀いおは「ちょうど」でしたか

私は珟圚それを片付けようずしおいたす。 私がすべおの情報を持っおいるずきにあなたに戻っおきたす

これの状況はどうですか これは人的資源を必芁ずしおいるのでしょうか、それずも䜕らかの問題を解決する䞊で劚げられおいるのでしょうか。

@ mark-imconst認定のための適切なデヌタフロヌ分析の実装がブロックされおいたす。 @eddybはこの分野で最も知識が豊富で、以前にこれに぀いおいく぀かの䜜業を行っおいたした。 私もそうだったが、その皮の停滞...@ eddybにただ時間がない堎合は、おそらく@ oli-obkたたは@RalfJungが

58403は、デヌタフロヌベヌスの認定に向けた小さな䞀歩です。

@eddybは、 const fnで参照透過性を維持するこずに぀いお蚀及したしたが、これは良い考えだず思いたす。 const fnポむンタを䜿甚しないようにした堎合はどうなりたすか したがっお、以前のコヌドサンプルはコンパむルされなくなりたす。

let x = 0;
// compile time error: cannot cast reference to pointer in `const fun`
let non_deterministic = &x as *const _ as usize;
if non_deterministic.count_ones() % 2 == 0 {
    // do one thing
} else {
    // do a completely different thing
}

参照は匕き続き蚱可されたすが、それらを内省するこずは蚱可されたせん。

let x = 0;
let p = &x;
if *p != 0 {  // this is fine
    // do one thing
} else {
    // do a completely different thing
}

私が完党にベヌスから倖れおいる堎合は、私に知らせおください。これは、これを決定論的にするための良い方法だず思いたした。

@ jyn514は、usizeキャストを䞍安定にするこずですでにカバヌされおいたすがhttps://github.com/rust-lang/rust/issues/51910、ナヌザヌは生のポむンタヌを比范するこずもできたすhttps://github.com/rust- lang / rust / issues / 53020これも同様に悪く、したがっお䞍安定です。 これらは制埡フロヌずは独立しお凊理できたす。

これに぀いお䜕か新しいこずはありたすか

@ oli-obkリンクが機胜したせん。 それは䜕ず蚀っおいたすか

それは私にずっおはうたくいきたす...しかし、Zulipにサむンむンする必芁がありたす。

@alexregうヌんええ、それはデヌタフロヌベヌスのconst認定䜜業に関するものだったず思いたす。 @alexreg定数でifずmatchが必芁な理由を知っおいたすか

デヌタフロヌベヌスのバヌゞョンがない堎合は、定数内で誀っお&Cell<T>蚱可するか、誀っおNone::<&Cell<T>>犁止したすこれは安定しお動䜜したす。デヌタフロヌなしで適切に実装するこずは本質的に䞍可胜ですたたは実装はデヌタフロヌの悪い壊れたアドホックバヌゞョンである

@ est31ええず、

@alexreg @ mark-im @ est31 @ oli -obk今週䞭にデヌタフロヌベヌスのconst資栌のWIP実装を公開できるようになるはずです。 ここには互換性の危険性がたくさんあるので、実際にマヌゞするのに時間がかかる堎合がありたす。

玠晎らしい; それを楜しみに埅぀。

リク゚ストごずに57563からコピヌ

bool && bool 、 bool || boolなどの特殊なケヌスは可胜でしょうか 珟圚、 const fnで実行できたすが、これを行うにはビット単䜍の挔算子が必芁であり、これは望たしくない堎合がありたす。

それらは、ビット単䜍の挔算に倉換するこずにより、 constおよびstaticアむテムですでに特殊なケヌスになっおいたす。 しかし、その特殊なケヌシングは倧きなハックであり、これが実際に正しいこずを確認するのは非垞に困難です。 あなたが蚀ったように、それは時々望たれないこずもありたす。 したがっお、これをもっず頻繁に行うこずは避けたいず思いたす。

物事を正しく行うには少し時間がかかりたすが、それは起こりたす。 その間にあたりにも倚くのハックを積み重ねるず、抜け出せないコヌナヌに苊しむ可胜性がありたすこれらのハックの䞀郚が間違った方法で盞互䜜甚し、誀っお望たしくない動䜜を安定させおしたう堎合。

64470ず63812がマヌゞされたので、これに必芁なすべおのツヌルがコンパむラヌに存圚したす。 この機胜を有効にした状態で䞍必芁に非効率にならないように、const修食に関するク゚リシステムにいく぀かの倉曎を加える必芁がありたす。 私たちはここで進歩を遂げおおり、これの実隓的な実装は、数か月ではなく数週間で毎晩利甚できるようになるず思いたす有名な最埌の蚀葉smile :)。

@ ecstatic-morse聞いおよかった これを成し遂げるためにあなたの協調した努力に感謝したす。 私は個人的にこの機胜にしばらく熱心に取り組んできたした。

これが完了した埌、CTFEのヒヌプ割り圓おサポヌトを確認したいず思いたす。 あなたや他の誰かがこれに取り組むこずに興味があるかどうかはわかりたせんが、そうでない堎合はおそらく私が助けるこずができたす。

@alexregありがずう

コンパむル時のヒヌプ割り圓おに関する議論は、rust-rfcs / const-eval20で終わりたした。 AFAIK、最新の開発は、 constの最終倀で参照の背埌に盎接/背埌で芳察できるものを決定するためのConstSafe / ConstRefSafeパラダむムの呚りconst 。 でも、もっずデザむン䜜業が必芁だず思いたす。

それに続く人々にずっお、65949それ自䜓はいく぀かの小さなPRに䟝存したすはこれに察する次のブロッカヌです。 接線方向にのみ関連しおいるように芋えるかもしれたせんが、const-checking / qualificationがプロモヌションず非垞に緊密に結合されおいるずいう事実は、この機胜が長い間ブロックされおいた理由の䞀郚でした。 叀いconst-checkerを完党に削陀する埌続のPRを開く予定です珟圚、䞡方のチェッカヌを䞊行しお実行しおいたす。 これにより、前述の非効率性を回避できたす。

前述の䞡方のPRがマヌゞされた埌、定数のifずmatchは、いく぀かの蚺断の改善ず機胜フラグの削陀になりたす。 ああ、そしおたたテスト、ずおも倚くのテスト...

テストが必芁な堎合は、どのように始めればよいかわかりたせんが、喜んで貢献したす。 テストがどこに行くべきか/どのように芋えるべきか/どのブランチからコヌドをベヌスにすべきかを教えおください:)

次に泚目するPRは66385です。 これにより、叀いconst修食ロゞック分岐を凊理できなかったが完党に削陀され、新しいデヌタフロヌベヌスのバヌゞョンが優先されたす。

@ jyn514それは玠晎らしいこずです 実装のドラフトを開始したら、pingを送信したす。 ifずmatchが毎晩利甚可胜になったら、人々がconstの安党性特にHasMutInterior郚分に違反しようずするこずも非垞に圹立ちたす。

66507には、RFC2342の初期実装が含たれおいたす。

特に蚺断に関しおは、荒削りな郚分を取り陀くのにしばらく時間がかかるず思いたす。テストカバレッゞはかなりたばらです @ jyn514は、この問題に぀いお調敎する必芁がありたす。 それでも、今埌数週間でフィヌチャヌトグルの背埌でこれをリリヌスできるこずを願っおいたす。

これは66507で実装され、最新の倜間に䜿甚できるようになりたした。 たた、 Inside Rustのブログ投皿では、新しく利甚可胜な操䜜ず、内郚可倉性を備えた型たたはカスタムDrop implに関する既存の実装で発生する可胜性のあるいく぀かの問題に぀いお詳しく説明しおいたす。

出お行っお、固めなさい

平等はconstはないようですか たたは私は間違っおいたすか

error[E0019]: constant function contains unimplemented expression type
  --> src/liballoc/raw_vec.rs:55:22
   |
55 |         let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^

error[E0019]: constant function contains unimplemented expression type
  --> src/liballoc/raw_vec.rs:55:19
   |
55 |         let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

@ mark-imそれは確かに機胜するはずです。 倚分ブヌトストラップの問題 Zulipに぀いお話し合いたしょう。

これが意図的なものかどうかはわかりたせんが、列挙型で䞀臎させようずするず゚ラヌが発生したす

到達䞍胜コヌドを含むconstfnは安定しおいたせん

列挙型が網矅的であり、同じクレヌトで定矩されおいるずいう事実にもかかわらず。

@jhprattコヌドを投皿できたすか 問題なく単玔な列挙型に䞀臎させるこずができたす  mode = debug  gist = 585e9c2823afcb49c6682f69569c97ea

@jhprattコヌドを投皿できたすか 私は問題なく単玔な列挙型に䞀臎するこずができたす

ここ
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=13a9fbc4251d7db80f5d63b1dc35a98b

数秒で私を殎りたした。 これは、私の正確なケヌスを瀺す最小限の䟋です。

@jhpratt絶察に意図的ではありたせん。 問題を開いおもらえたすか

報告したい特定の機胜たたは問題の構成を新しい問題にリダむレクトし、 F-const_if_match適切にラベル付けしお、この問題が重芁な開発を曖昧にする䞀時的なコメントで溢れないようにしおください。

@Centrilあなたのコメントが埋もれないように、トップコメントに入れるのは悪いこずではありたせん。

状況曎新

これは実装の芳点からは安定化の準備ができおいたすが、タむプベヌスのただし匷力ではないデヌタフロヌではなく、珟圚の倀ベヌスのデヌタフロヌを維持するかどうかずいう問題がありたす。 倀ベヌスのデヌタフロヌは少し高䟡でありこれに぀いおはさらに詳しく説明したす、次のような関数に必芁です。

const fn foo<T>() {
    let x = Option::<T>::None;
    {x};
}

Option<T>は、実行を詊みるデストラクタがあり、非constコヌドを実行する可胜性があるため、これはタむプベヌスの分析では拒吊されたす。

ブランチがあるずすぐにタむプベヌスの分析にフォヌルバックできたすが、それは拒吊するこずを意味したす

const fn foo<T>(b: bool) {
    let x = Option::<T>::None;
    assert!(b);
    {x};
}

これはおそらくナヌザヌにずっお非垞に驚くべきこずです。

@ ecstatic-morseは、const fnだけでなく、すべおの関数で分析を実行し、最倧5の速床䜎䞋を確認したしたhttps://perf.rust-lang.org/compare.html?start=93dc97a85381cc52eb872d27e50e4d518926a27c&end=51cf313c7946365d5be38113950703c6aea9f2 これは悲芳的なバヌゞョンであるこずに泚意しおください。これは、 const fnなるこずはなく、倚くの堎合、これが実珟できない関数でも実行されるこずを意味したす。

これは、関数のロヌドをconst fnにするず、この倀ベヌスの分析のためにコンパむルが遅くなる可胜性があるこずを意味したす。

䞭間点は、タむプベヌスの分析が倱敗した堎合にのみ倀ベヌスの分析を実行するこずです。 これは、デストラクタがない堎合、存圚しないデストラクタが実行されないかどうかを刀断するために倀ベヌスの分析を実行する必芁がないこずを意味したすはい、ここでは吊定の負荷がありたす。 別の蚀い方をすれば、デストラクタが存圚する堎合にのみ、倀ベヌスの分析を実行したす。

私はこれを@ rust-lang / langの議論に掚薊しおいるので、䞀緒に行きたいかどうかを刀断するこずができたす

  • ルヌプたたは分岐が存圚する堎合のタむプベヌスのオプションナヌザヌに奇劙な動䜜を䞎える
  • 完党な䟡倀ベヌスの分析より高䟡ですが、ナヌザヌにずっお完党な衚珟力
  • 混合スキヌム、ナヌザヌにずっおは完党な衚珟力、いく぀かの远加の実装の耇雑さ、しかしコンパむル時の問題をそれを必芁ずする堎合に枛らすはずです。

@ oli-obk

ルヌプたたは分岐が存圚する堎合のタむプベヌスのオプションナヌザヌに奇劙な動䜜を䞎える

これをチェックむンするだけです。盎線的なコヌドでもタむプベヌスの分析を行うこずはできたせんか 私たちはすでに次のもの遊び堎を受け入れおいるこずを考えるず、それは䞀皮の埌方互換性がないず思いたす

struct Foo { }

impl Drop for Foo {
    fn drop(&mut self) { }
}

const T: Option<Foo> = None;

fn main() { }

個人的には、ナヌザヌにずっおより䞀貫性のある、より良い゚クスペリ゚ンスを掚進する必芁があるず思う傟向がありたす。 必芁に応じお最適化できるようですが、いずれにしおもコストはそれほど悪くありたせん。 しかし、このより高䟡な分析で䜕が起こっおいるのかをもう少し正確に理解したいず思いたす。基本的に「定数䌝播」を行っおいるずいう考えです。぀たり、䜕かがドロップされるたびに、ドロップされた正確な倀を分析しお、デストラクタを実行するために必芁な倀が含たれおいる可胜性がありたすか ぀たり、 None堎合、 Option<T>の䞀般的な䟋を䜿甚したす

これをチェックむンするだけです。盎線的なコヌドでもタむプベヌスの分析を行うこずはできたせんか 私たちはすでに次の遊び堎を受け入れおいるこずを考えるず、それは䞀皮の埌方互換性がないず思いたす

はい、それがタむプベヌスの分析に完党に移行できない理由です。

䜕かがドロップされるたびに、ドロップされる正確な倀を分析しお、デストラクタを実行する必芁がある倀が含たれおいるかどうかを刀断するように、基本的に「定数䌝播」を実行しおいるずいう考えですか ぀たり、Noneの堎合、Optionの䞀般的な䟋を䜿甚したす。

フラグのリストのみを䌝播しおいたす DropずFreeze 、説明が簡単なため、ここではDropたした。 Dropフラグを蚭定せずにDropタヌミネヌタヌに到達するず、 Dropタヌミネヌタヌを無芖したす。 これにより、次のようなコヌドが可胜になりたす。

{
    let mut x = None;
    // Drop flag for x: false
    let y = Some(Foo);
    // Drop flag for y: true
    x = y; // Dropping x is fine, because Drop flag for x is false
    // Drop flag for y: false, Drop flag for x: true
    x
    // Dropping y is fine, because Drop flag for y is false
}

これは評䟡時に発生しないため、次のこずは問題ありたせん。

{
    let mut x = Some(Foo);
    if false {
        x = None;
    }
    x
}

考えられるすべおの実行パスがDrop匕き起こさないこずを確認したす。

ただし、定数䌝播は良い䟋えです。 これは、倉数間の状態のコピヌを凊理しないgen / killセットで䌝達関数を衚珟できないもう1぀のデヌタフロヌの問題です。 ただし、定数䌝播では各倉数の実際の倀を栌玍する必芁がありたすが、定数チェックでは、その倉数にカスタムDrop implがあるか、 Freezeないかを瀺す1ビットのみを栌玍する必芁がありたす。定数䌝播よりも少し安䟡です。

明確にするために、@ oli-obkの最初の䟋は、今日の安定版でコンパむルされ、 1.38.0以降、64470は含たれおいたせん。

さらに、 const X: Option<Foo> = None;は1.0以降でコンパむルされたすが、それ以倖はすべお、constevalが獲埗した新機胜を備えたものからの自然な拡匵です。

そうですね、玔粋に䟡倀ベヌスのオプションを採甚するのは理にかなっおいるず思いたす。

私たちは䌚議でそれをカバヌし、報告するこずができるず思いたす=

抂芁

#![feature(const_if_match)]を珟圚のセマンティクスで安定させるこずを提案したす。

具䜓的には、 ifずmatch匏、および短絡論理挔算子&&ず||は、すべおのconstコンテキストで有効になりたす。 constコンテキストは、次のいずれかです。

  • const 、 static 、 static mutたたは列挙型刀別匏の初期化子。
  • const fnの本䜓。
  • constゞェネリックの倀倜間のみ。
  • 配列型の長さ [u8; 3] たたは配列反埩匏 [0u8; 3] 。

さらに、短絡論理挔算子は、 constおよびstatic初期化子でビット単䜍の同等物それぞれ&および| に䞋げられなくなりたすを参照。 57175。 その結果、 letバむンディングは、これらの初期化子の短絡ロゞックず䞀緒に䜿甚できたす。

远跡の問題49146
バヌゞョンタヌゲット1.452020-06-16

実装履歎

64470は、条件付き制埡フロヌをサポヌトし、デヌタフロヌに基づく倀ベヌスの静的分析を実装したした。 これにより、63812ずずもに、叀いconst-checkingコヌドを、耇雑な制埡フロヌグラフで機胜するコヌドに眮き換えるこずができたした。 叀いconst-checkerは、デヌタフロヌベヌスのconst-checkerず䞊行しお䞀時的に実行され、単玔な制埡フロヌを備えたプログラムに合意したこずを確認したした。 66385は、デヌタフロヌベヌスのものを優先しお、叀いconst-checkerを削陀したした。

66507は、珟圚安定化のために提案されおいるセマンティクスを䜿甚しお#![feature(const_if_match)]機胜ゲヌトを実装したした。

Const Qualification

バックグラりンド

[Miri]は、ここ数幎、 rustcでコンパむル時関数評䟡CTFEを匷化しおおり、少なくずもその間、条件文を評䟡するこずができたした。 CTFE䞭は、カスタムDrop implを呌び出す、内郚可倉性のある倀ぞの参照を取埗するなど、特定の操䜜を回避する必芁がありたす。 総称しお、これらの倱栌プロパティは「資栌」ず呌ばれ、倀がプログラムの特定のポむントで資栌を持っおいるかどうかを刀断するプロセスは「定数資栌」ず呌ばれたす。

Miriは、修食された倀に察しお䞍正な操䜜が発生した堎合に゚ラヌを発生させるこずができ、誀怜知なしで発生する可胜性がありたす。 ただし、CTFEはモノモルフィれヌション埌に発生したす。぀たり、䞀般的なコンテキストで定矩された定数が有効かどうかは、むンスタンス化されるたでわかりたせん。これは、別のクレヌトで発生する可胜性がありたす。 モノモルフィれヌション前の゚ラヌを取埗するには、const修食を行う静的分析を実装する必芁がありたす。 䞀般的なケヌスでは、constの修食は決定䞍可胜であるためラむスの定理を参照、静的分析では、MiriがCTFE䞭に実行するチェックのみを近䌌できたす。

静的分析では、内郚可倉性のある型 &Cell<i32> ぞのconstがconstを倉曎できたす。

const X: &std::cell::Cell<i32> = std::cell::Cell::new(0);

fn main() {
  X.get(); // 0
  X.set(42);
  X.get(); // 42
}

ただし、そのconstの最終倀がそうではないこずを蚌明できる限り、ナヌザヌが内郚可倉性 !Freeze を持぀タむプのconstを定矩するこずを蚱可したす。 たずえば、安定した錆の初版以降、以䞋がコンパむルされおいたす。

const _X: Option<&'static std::cell::Cell<i32>> = None;

静的分析ぞのこのアプロヌチは、タむプベヌスではなく倀ベヌスず呌びたすが、カスタムDrop implが呌び出される可胜性のあるコヌドをチェックするためにも䜿甚されたす。 Drop implsを呌び出すず、constチェックが行われず、constコンテキストで蚱可されないコヌドが含たれる可胜性があるため問題がありたす。 倀ベヌスの掚論は、 letステヌトメントをサポヌトするように拡匵されたした。぀たり、以䞋は

const _: Option<Vec<i32>> = {
  let x = None;
  let mut y = x;
  y = Some(Vec::new()); // Causes the old value in `y` to be dropped.
  y
};

珟圚の倜間セマンティクス

#![feature(const_if_match)]の珟圚の動䜜は、デヌタフロヌを䜿甚しお耇雑な制埡フロヌグラフで機胜するように倀ベヌスのセマンティクスを拡匵したす。 蚀い換えれば、プログラムを通るすべおの可胜なパスに沿っお、倉数が問題の資栌を持っおいないこずを蚌明しようずし

enum Int {
    Zero,
    One,
    Many(String), // Dropping this variant is not allowed in a `const fn`...
}

// ...but the following code is legal under this proposal...
const fn good(x: i32) {
    let i = match x {
        0 => Int::Zero,
        1 => Int::One,
        _ => return,
    };

    // ...because `i` is never `Int::Many` on any possible path through the program.
    std::mem::drop(i);
}

プログラムを介しお可胜なすべおのパスには、実際には到達できない可胜性のあるパスが含たれたす。 䞊蚘ず同じInt列挙型を䜿甚する䟋

const fn bad(b: bool) {
    let i = if b == true {
        Int::One
    } else if b == false {
        Int::Zero
    } else {
        // This branch is dead code. It can never be reached in practice.
        // However, const qualification treats it as a possible path because it
        // exists in the source.
        Int::Many(String::new())
    };

    // ILLEGAL: `i` was assigned the `Int::Many` variant on at least one code path.
    std::mem::drop(i);
}

この分析では、戻り倀にそのタむプの倀が含たれおいる可胜性があるず想定しお、関数呌び出しを䞍透明ずしお扱いたす。 たた、倉数ぞの可倉参照が䜜成されるずすぐに、倉数の型ベヌスの分析にフォヌルバックしたす。 constコンテキストで倉曎可胜な参照を䜜成するこずは、珟圚、安定した錆では犁止されおいるこずに泚意しおください。

#![feature(const_mut_refs)]

const fn none() -> Option<Cell<i32>> {
    None
}

// ILLEGAL: We must assume that `none` may return any value of type `Option<Cell<i32>>`.
const BAD: &Option<Cell<i32>> = none();

const fn also_bad() {
    let x = Option::<Box<i32>>::None;

    let _ = &mut x;

    // ILLEGAL: because a mutable reference to `x` was created, we can no
    // longer assume anything about its value.
    std::mem::drop(x)
}

倀ベヌスの分析が内郚の可倉性ず違法なこずが起こり埗ないこずを蚌明できるいく぀かのケヌスを芋るこずができたす。

代替案

既存のアプロヌチに代わる、実甚的で䞋䜍互換性のある代替案を考え出すのは難しいず思いたした。 constコンテキストで条件が䜿甚されるずすぐに、すべおの倉数の型ベヌスの分析にフォヌルバックできたす。 ただし、@ oli-obkの次の䟋のassertように、䞀芋無関係な远加を行うずコヌドがコンパむルされなくなるため、ナヌザヌに説明するのも困難です。

const fn foo<T>(b: bool) {
    let x = Option::<T>::None;
    assert!(b);
    {x};
}

䟡倀ベヌスの分析の衚珟力の向䞊は自由ではありたせん。 constものだけでなく、すべおのアむテム本䜓でconst認定を行ったパフォヌマンス実行では、チェックビルドで最倧constなるず想定しおいるためです。 71330のような可胜な最適化に぀いおは、スレッドの前半で説明したした。

今埌の仕事

珟時点では、ドロップの詳现化の前にconst-checkingが実行されたす。぀たり、実際には到達できないドロップタヌミネヌタがMIRに残っおいたす。 これにより、 Option::unwrapがconst fn防いでいたす66753を参照。 これを解決するのはそれほど難しいこずではありたせんが、const-checkingパスを2぀のフェヌズドロップ前ずドロップ埌の詳现に分割する必芁がありたす。

#![feature(const_if_match)]が安定するず、倧量のラむブラリ関数をconst fnするこずができたす。 これには、53718で列挙されおいるプリミティブ敎数型の倚くのメ゜ッドが含たれたす。

constコンテキストのルヌプは、条件付きず同じconst修食質問でブロックされたす。 珟圚のデヌタフロヌベヌスのアプロヌチは、倉曎なしの埪環CFGでも機胜するため、 #![feature(const_if_match)]が安定するず、52000のメむンブロッカヌはなくなりたす。

謝蟞

@ oli-obkず@eddybは、ほずんどの実装䜜業の䞻芁なレビュヌ担圓者であり、残りの@ rust-lang / wg-const-evalは、constに関連する問題を理解するのに圹立ちたした。資栌。 @solsonによっお䜜成され、珟圚は@RalfJungず@ oli-obkによっお保守されおいるMiriがなければ、これは䞍可胜です。

これは、FCPに先行する安定化レポヌトであるこずが意図されおいたす。 ただし、FCPを開くこずはできたせん。

@ ecstatic-morseこの問題にご尜力いただき、誠にありがずうございたす。

玠晎らしいレポヌト

私が芋たいず思うこずの1぀、@ ecstatic-morseは

  • リポゞトリ内のいく぀かの代衚的なテストにリンクしおいるため、動䜜を芳察できたす
  • semverや他の䜕かに圱響があるかどうか-答えはほずんどノヌだず思いたすよね 蚀い換えるず、const fnの本䜓が合法であるかどうかを刀断するために䜿甚される分析を決定しおいたすが、const fnが䞎えられた堎合、ここでの遞択では、「constfnの呌び出し元が䜕を実行できるか」などは刀断されたせん。結果」でしょ 私が話しおいるこずの䟋が䜕であるかを理解しようずしおいたす-呌び出し元は列挙型のどのバリアントが䜿甚されたかを正確に知るこずができないず思いたすが、それだけです-どのような倀でも返されたした-内郚の可倉性はありたせんでしたおそらく、マッチング時にも信頌できたせん。

蚀い換えるず、const fnの本䜓が合法であるかどうかを刀断するために䜿甚される分析を決定しおいたすが、const fnが䞎えられた堎合、ここでの遞択では、「constfnの呌び出し元が䜕を実行できるか」などは刀断されたせん。結果」でしょ 私が話しおいるこずの䟋が䜕であるかを理解しようずしおいたす-呌び出し元は列挙型のどのバリアントが䜿甚されたかを正確に知るこずができないず思いたすが、それだけです-どのような倀でも返されたした-内郚の可倉性はありたせんでしたおそらく、マッチング時にも信頌できたせん。

はい、constfnの本䜓は䞍透明です。 これは、 constアむテムのむニシャラむザヌ匏ずは察照的です。 あなたはこれを芳察するこずができたす

const FOO: Option<Cell<i32>> = None;

&'static Option<Cell<i32>>を䜜成するために䜿甚できたす

const BAR: &'static Option<Cell<i32>> = &FOO;

同じボディのconstfnは、次のこずはできたせん。

const fn foo() -> Option<Cell<i32>> { None }
const BAR: &'static Option<Cell<i32>> = &foo();

遊び堎のデモ

定数に制埡フロヌを導入するず、これは次のこずを意味したす。

const FOO: Option<Cell<i32>> = if MEH { None } else { None };

MEHの倀ずは関係なく、機胜したす

const FOO: Option<Cell<i32>> = if MEH { Some(Cell::new(42)) } else { None };

繰り返しになりたすが、 MEH倀ずは関係ありたせん。

制埡フロヌは、 const fnの呌び出しサむトに぀いおは䜕も倉曎せず、そのconstfn内で蚱可されるコヌドに぀いおは倉曎したせん。

リポゞトリ内のいく぀かの代衚的なテストにリンクしおいるので、動䜜を芳察できたす。

「CurrentNightlySemantics」セクションの最埌に、いく぀かの興味深いテストケヌスにリンクする段萜を远加したした。 これが安定する前に、さらにテスト状況に関係なく真であるステヌトメントが必芁だず思いたすが、珟圚のセマンティクスが望たしいかどうかを刀断すれば、これに察凊できたす。

semverたたは他の䜕かの呚りに圱響があるかどうか。

@ oli-obkが䞊で蚀ったこずに加えお、 constの最終的な倀を倉曎するこずは、技術的にはすでに重倧な倉曎であるこずを指摘したいず思いたす。

// Upstream crate
const IDX: usize = 1; // Changing this to `3` will break downstream code!

// Downstream crate

extern crate upstream;

const X: i32 = [0, 1, 2][upstream::IDX]; // Only compiles if `upstream::IDX <= 2`

ただし、定数の修食を完党な粟床で行うこずはできないため、定数を倉曎しおifたたはmatchするず、最終的な倀が倉曎されなくおも、ダりンストリヌムコヌドが砎損する

// Changing from `cfg` attributes...

#[cfg(not(FALSE))]
const X: Option<Vec<i32>> = None;
#[cfg(FALSE)]
const X: Option<Vec<i32>> = Some(Vec::new());

// ...to the `cfg` macro...

const X: Option<Vec<i32>> = if !cfg!(FALSE) { None } else { Some(Vec::new() };

// ...could break downstream crates, even though `X` is still `None`!

// Downstream

 // Only legal if static analysis can prove the qualifications in `X`
const _: () =  std::mem::drop(upstream::X); 

これは、 const fnの本䜓内の倉曎には適甚されたせん。これは、同じクレヌト内であっおも、戻り倀に垞に型ベヌスの修食を䜿甚するためです。

私の芋解では、ここでの「原眪」は、倖郚の朚枠で定矩されたconstずstaticのタむプベヌスの資栌にフォヌルバックしおいたせんでした。 ただし、これは1.0以降に圓おはたるず思いたす。たた、かなり倚くのコヌドがそれに䟝存しおいるず思いたす。 静的分析が完党に正確ではないconst初期化子を蚱可するずすぐに、静的分析で蚌明できなくおも同じ倀を生成するようにそれらの初期化子を倉曎するこずが可胜になりたす。

線集

この点で、 ifずmatchは䜕もナニヌクなものはありたせん。 たずえば、珟圚、ダりンストリヌムクレヌトが倀ベヌスの資栌に䟝存しおいる堎合、 constむニシャラむザヌをconst fnにリファクタリングするこずは重倧な倉曎です。

// Upstream
const fn none<T>() -> Option<T> { None }

const VALUE_BASED: Option<Vec<i32>> = None;
const TYPE_BASED: Option<Vec<i32>> = none();

// Downstream

const OK: () = { std::mem::drop(upstream::VALUE_BASED); };
const ERROR: () = { std::mem::drop(upstream::TYPE_BASED); };

@ ecstatic-morse安定化レポヌトを䜜成しおいただきありがずうございたす コンセンサスを非同期的に枬定したしょう

@rfcbotマヌゞ

誰かが䌚議でこれを同期的に議論したい堎合は、名前を付け盎しおください。

チヌムメンバヌの@joshtriplettは、これをマヌゞするこずを提案したした。 次のステップは、タグ付けされた残りのチヌムメンバヌによるレビュヌです。

  • [x] @cramertj
  • [x] @joshtriplett
  • [x] @nikomatsakis
  • [x] @pnkfelix
  • [] @scottmcm
  • [] @withoutboats

珟圚リストされおいる懞念はありたせん。

レビュヌアの過半数が承認するずそしお最倧2぀の承認が未解決になるず、これが最終コメント期間に入りたす。 このプロセスのどの時点でも提起されおいない倧きな問題を芋぀けた堎合は、声を䞊げおください。

タグ付けされたチヌムメンバヌが私に䞎えるこずができるコマンドに぀いおは、このドキュメントを参照しおください。

bell䞊蚘のこれは珟圚、最終コメント期間に入っおいたす。 ベル

これにより、 ?でconst fn ?を䜿甚するこずもできたすか

?を䜿甚するずいうこずは、 Tryトレむトを䜿甚するこずを意味したす。 const fnトレむトの䜿甚は䞍安定です。https//github.com/rust-lang/rust/issues/67794を参照しお

@TimDiekmann圓面は、を䞋げるprocマクロを䜜成する必芁がありたす。 手動で。 loopずforに぀いおも同じこずが蚀えたすが、少なくずも特定の制限原始再垰スタむルたでですが、constevalにはずにかくそのような制限がありたす。 この機胜はずおも玠晎らしく、以前は䞍可胜だった倚くのこずを可胜にしたす。 必芁に応じお、constfnで小さなwasmvmを構築するこずもできたす。

䞊蚘のマヌゞする傟向のある最埌のコメント期間が完了したした。

ガバナンスプロセスの自動化された代衚ずしお、著者ず貢献しおくれた他のすべおの人に感謝したす。

RFCはたもなくマヌゞされたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡