Что такое «точка последовательности» / «последовательность до» правила в Rust?

Какие правила в Rust, аналогичны правилам, описанным здесь http://en.cppreference.com/w/cpp/language/eval_order для C ++?

На данный момент я нашел опытным путем, что
1) Аргументы функций оцениваются в прямом порядке
2) Все встроенные операции с побочными эффектами (=, + =, — = и т. Д.) Возвращают единицу, поэтому сложно (но возможно) составить выражения, которые бы показывали UB в C ++.
Один пример:

let mut a = 1i;
let b = 2i;
let c = 3i;
let d = (a = b) == (a = c); // What is a? (a is actually 3)

3) Кажется, что вызовы функций упорядочены как в C ++
4) Кажется, что встроенные операции упорядочены так, как если бы они были вызовами функций (методов), то есть порядок вычисления привязан к приоритету оператора

Верны ли мои выводы? Какова точная модель оценки?

5

Решение

Я не верю, что это было четко определено, мое понимание руководство ничего не появилось Тем не менее, я могу гарантировать, что эти вещи не будут неопределенным поведением (Rust явно избегает UB снаружи unsafe код), и я был бы удивлен, если бы это было что-нибудь, кроме «слева направо», то есть порядок, который вы вывели. Хотя, разрешение на # 6268 может привести к тому, что методы оценят получателя последним (или, может быть, нет, это всего лишь одна из возможностей).

я открыл # 15300.


Кстати, если вы исследуете это, вы можете заставить компилятор разделить симпатичные графы потоков управления с помощью точный порядок оценки (примечание. Это все внутренние API-интерфейсы, поэтому на них нельзя полагаться, с большей вероятностью, чем обычно, произойдет сбой компилятора, и он не скрывает детали реализации компилятора: он в основном предназначен для людей, работающих над rustc).

Как указывает @pnkfelix, компилятор не использует CFG для генерации кода (по состоянию на 2014-07-02), а это значит, что CFG не гарантирует точную точность.

Например. взяв урезанную версию одного из примеров @ ChrisMorgan:

fn foo(_: (), x: int) -> int {
x
}

fn main() {
let mut a = 1;
{ // A
a * foo(a = 3, a)
};
}

Мы хотим, чтобы компилятор разделил граф потока операций операторов / выражений в некотором блоке (т.е. { ... }), что можно сделать через --pretty flowgraph=<nodeid> вариант для компилятора, но для этого нам нужно иметь идентификатор нашего блока интересов. В этом случае блок, который мы хотим A, Чтобы получить идентификатор скомпилировать с rustc --pretty expanded,identified (обратите внимание, что просто с помощью identified это бессмысленная реликвия: теперь идентификаторы назначаются только после расширения макроса):

#![feature(phase)]
#![no_std]
#![feature(globs)]
#[phase(plugin, link)]
extern crate std = "std#0.11.0-pre";
extern crate native = "native#0.11.0-pre";
use std::prelude::*;
fn foo(_ /* pat 7 */: (), x /* pat 11 */: int) -> int { (x /* 15 */) } /*
block 14 */ /* 4 */

fn main() {
let mut a /* pat 22 */ = (1 /* 23 */);
({
((a /* 28 */) *
((foo /* 30
*/)(((a /* 32 */) = (3 /* 33 */) /* 31 */), (a /* 34 */)) /*
29 */) /* 27 */)
} /* block 26 */ /* 25 */);
} /* block 18 */ /* 16 */

Много неприглядного барахла, но нам нужно в комментарии /* block 26 */, rustc --pretty flowgraph=26 дает точечный файл, который отображает следующее. Вы можете обратиться к указанному выше идентификатору источника, чтобы точно определить, что представляет собой каждое выражение ( id = .. немного):

CFG

(извините за длину, очевидно, что этот код не имел ветвления и поэтому является просто длинной цепочкой операций.)

FWIW, это выражение оценивает 9в то время как я ожидал 3 (и график потока управления подтверждает, что изолированный a на LHS оценивается после RHS, в том числе a = 3 там). Я поднял это на # 15300 (е: и сейчас изолировал это до странной разницы в порядке оценки).

5

Другие решения


По вопросам рекламы [email protected]