目前,如果您尝试对 const 向量进行索引,在 const expr 中,我们会报告编译后期的边界溢出——在翻译期间。 我们应该更早地注意到它,在 const 评估阶段。
显然,这产生的“错误”不会导致编译失败——将生成代码并且 rustc 将返回 0。LLVM 会抱怨索引是否物理上越界,目前这总是等价于越界index (我认为),但对于 const 切片来说情况并非如此。
这在测试期间尤其出乎意料,它(显然除了快速检查?)在成功时不显示输出/错误。
对 0.6 不重要; 去里程碑
提名里程碑 5,生产就绪
接受生产就绪里程碑
作为我认为这是在谈论的一个例子:
static a: &'static [int] = &[];
static b: int = a[1];
fn main() {}
产量
$ rustc foo.rs
foo.rs:2:16: 2:19 error: const index-expr is out of bounds
foo.rs:2 static b: int = a[1];
^~~
Assertion failed: (ReqTy && "extractvalue indices invalid!"), function getExtractValue, file ../../../../src/llvm/lib/IR/Constants.cpp, line 1982.
zsh: abort rustc foo.rs
我们根本就遇到了 LLVM 断言,这似乎很糟糕。
接受 P 低。
分类: @alexcrichton的(9 个月大)示例在语法上仍然有效(是的!)并且仍然因该断言而失败(嘘!)。
我相信这是固定的。
如果您更新@alexcrichton的示例:
#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];
fn main() {}
它现在编译成功,没有任何抱怨。
只有当您尝试使用无效值B
时, rustc
才会遇到问题。
#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];
fn main() {
println!("B={}", B);
}
<anon>:3:18: 3:22 error: const index-expr is out of bounds
<anon>:3 const B: usize = A[1];
^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/lib/IR/Constants.cpp:2174: static llvm::Constant* llvm::ConstantExpr::getExtractValue(llvm::Constant*, llvm::ArrayRef<unsigned int>, llvm::Type*): Assertion `ReqTy && "extractvalue indices invalid!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134
错误:无法按值引用其他静态,请改用地址运算符或常量
是的,看起来不错。
等等, @JustAPerson的例子对我来说似乎不太好。 重新开放。
我认为现在已经解决了这个问题:
$ cat foo.rs
#![allow(dead_code)]
const A: &'static [usize] = &[];
const B: usize = A[1];
fn main() {
println!("B={}", B);
}
$ rustc foo.rs
foo.rs:3:18: 3:22 error: const index-expr is out of bounds
foo.rs:3 const B: usize = A[1];
^~~~
error: aborting due to previous error
$ rustc --version
rustc 1.0.0-dev (a691f1eef 2015-04-15) (built 2015-04-15)
因此,在过去 11 天的某个时间:
hello.rs:3:18: 3:22 error: const index-expr is out of bounds
hello.rs:3 const B: usize = A[1];
^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
soooo 好像已经退步了?
呃,这是我的错误。 我使用在禁用 LLVM 断言的情况下编译的工具链制作了上述报告(我不知道这是默认设置)。
(你好,我正在努力帮助新人更容易理解 E-easy 问题:smile_cat:)
我使用在禁用 LLVM 断言的情况下编译的工具链制作了上述报告(我不知道这是默认设置)。
听起来为了重现此问题,您必须使用使用非默认设置编译的工具链? 如果是这样,如何去做呢?
在这里应该发生的事情有点令人困惑,所有关闭重新开放的事情都在进行。 有人可以澄清预期的行为是什么以及它与当前行为有何不同?
./configure --enable-llvm-assertions
但是,您可以每晚使用 Rust,因为在那里启用了 LLVM 断言。 http://is.gd/X2RztV仍然无法在夜间断言:
<anon>:2:17: 2:21 error: const index-expr is out of bounds
<anon>:2 static b: i32 = a[1];
^~~~
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/include/llvm/Support/Casting.h:237: typename llvm::cast_retty<X, Y*>::ret_type llvm::cast(Y*) [with X = llvm::SequentialType; Y = llvm::Type; typename llvm::cast_retty<X, Y*>::ret_type = llvm::SequentialType*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
Aborted (core dumped)
playpen: application terminated with error code 134
看起来我在 2013 年苦恼的事情已经解决了:如果 rustc 给出const index-expr is out of bounds
错误,即使 LLVM 断言被禁用,它也会以失败状态退出(并且不写入输出文件)。 我认为翻译过去无法访问检查所做的会话/错误内容,因为它不应该能够找到检查遗漏的错误? 但现在看来不是这样了。
我过去的自己提到的另一件事……听起来好像我们过去只是将索引传递给 LLVM,即使我们知道它超出范围,但现在我们构造了一个undef
。 但无论如何,这部分都得到了处理,因为现在错误得到了正确处理。
至于我们今天看到的 LLVM 断言,我有一个猜测。 报告错误后,我们这样做:
C_undef(type_of::type_of(cx, bt).element_type())
我认为我们想要这样的东西(未经测试):
C_undef(val_ty(arr).element_type())
因为如果被索引的值是切片或指针,那么bt
(它的类型)将不会被数组类型表示,所以element_type
将失败。
但是, @graydon打开这个问题的目的,以及引用这个问题的代码中的注释建议做什么,是将该检查移动到编译的早期阶段。 看起来#25370/#25570 可能会或多或少地实现这一目标?
我认为现在已经完全解决了。 @oli-obk ?
不行,需要在check_const
解决,需要把当前报告位置改成bug位置
@oli-obk 这是一个简单的解决方法,如果是这样,您是否想指导它并留下一些提示,以便新人可以尝试破解它?
虽然这是一个简单的修复(你基本上可以窃取 https://github.com/rust-lang/rust/blob/master/src/librustc/middle/check_const.rs#L470-L490 并以ExprIndex
然后将 https://github.com/rust-lang/rust/blob/master/src/librustc_trans/trans/consts.rs#L708-L712 变成一个错误/ unimplemented!()
)。
但这也将是一个重大变化,因为未使用的const ARR: [u32; 0] = []; const X: u32 = ARR[5];
目前不会导致编译错误。 而check_const
也会检查未使用的常量。
此外,它最终会进行两次所有 const 评估。 一旦它成为一个问题,就可以通过缓存常量来补救。
当然,可以通过简单地发出const_err
lint 来补救重大变化。
这似乎已经“解决”了(可能是由于 MIRI),因为它现在在使用时抛出E0080 ,而不是 LLVM 断言。 如果访问权限未使用,它仍然会通过。
未使用 const 时丢失的 lint 将由https://github.com/rust-lang/rust/pull/50110修复
是的,我认为我们在 6 年后解决了这个问题 :laughing:
最有用的评论
是的,我认为我们在 6 年后解决了这个问题 :laughing: