mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-07 04:23:30 +00:00
Auto merge of #56160 - oli-obk:const_fn_let, r=nikomatsakis
Fix various aspects around `let` bindings inside const functions * forbid `let` bindings in const contexts that use short circuiting operators * harden analysis code against derefs of mutable references Initially this PR was about stabilizing `let` bindings, but too many flaws were exposed that need some more testing on nightly
This commit is contained in:
commit
cb84844e83
@ -121,7 +121,6 @@
|
||||
#![feature(const_slice_len)]
|
||||
#![feature(const_str_as_bytes)]
|
||||
#![feature(const_str_len)]
|
||||
#![feature(const_let)]
|
||||
#![feature(const_int_rotate)]
|
||||
#![feature(const_int_wrapping)]
|
||||
#![feature(const_int_sign)]
|
||||
|
@ -149,6 +149,14 @@ pub struct Mir<'tcx> {
|
||||
/// This is used for the "rust-call" ABI.
|
||||
pub spread_arg: Option<Local>,
|
||||
|
||||
/// Mark this MIR of a const context other than const functions as having converted a `&&` or
|
||||
/// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop
|
||||
/// this conversion from happening and use short circuiting, we will cause the following code
|
||||
/// to change the value of `x`: `let mut x = 42; false && { x = 55; true };`
|
||||
///
|
||||
/// List of places where control flow was destroyed. Used for error reporting.
|
||||
pub control_flow_destroyed: Vec<(Span, String)>,
|
||||
|
||||
/// A span representing this MIR, for error reporting
|
||||
pub span: Span,
|
||||
|
||||
@ -167,6 +175,7 @@ impl<'tcx> Mir<'tcx> {
|
||||
arg_count: usize,
|
||||
upvar_decls: Vec<UpvarDecl>,
|
||||
span: Span,
|
||||
control_flow_destroyed: Vec<(Span, String)>,
|
||||
) -> Self {
|
||||
// We need `arg_count` locals, and one for the return place
|
||||
assert!(
|
||||
@ -191,6 +200,7 @@ impl<'tcx> Mir<'tcx> {
|
||||
spread_arg: None,
|
||||
span,
|
||||
cache: cache::Cache::new(),
|
||||
control_flow_destroyed,
|
||||
}
|
||||
}
|
||||
|
||||
@ -421,6 +431,7 @@ impl_stable_hash_for!(struct Mir<'tcx> {
|
||||
arg_count,
|
||||
upvar_decls,
|
||||
spread_arg,
|
||||
control_flow_destroyed,
|
||||
span,
|
||||
cache
|
||||
});
|
||||
@ -1748,6 +1759,9 @@ pub enum StatementKind<'tcx> {
|
||||
/// (e.g., inspecting constants and discriminant values), and the
|
||||
/// kind of pattern it comes from. This is in order to adapt potential
|
||||
/// error messages to these specific patterns.
|
||||
///
|
||||
/// Note that this also is emitted for regular `let` bindings to ensure that locals that are
|
||||
/// never accessed still get some sanity checks for e.g. `let x: ! = ..;`
|
||||
FakeRead(FakeReadCause, Place<'tcx>),
|
||||
|
||||
/// Write the discriminant for a variant to the enum Place.
|
||||
@ -2984,6 +2998,7 @@ BraceStructTypeFoldableImpl! {
|
||||
arg_count,
|
||||
upvar_decls,
|
||||
spread_arg,
|
||||
control_flow_destroyed,
|
||||
span,
|
||||
cache,
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ CloneTypeFoldableAndLiftImpls! {
|
||||
usize,
|
||||
::ty::layout::VariantIdx,
|
||||
u64,
|
||||
String,
|
||||
::middle::region::Scope,
|
||||
::syntax::ast::FloatTy,
|
||||
::syntax::ast::NodeId,
|
||||
|
@ -849,15 +849,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Mir::new(self.cfg.basic_blocks,
|
||||
self.source_scopes,
|
||||
ClearCrossCrate::Set(self.source_scope_local_data),
|
||||
IndexVec::new(),
|
||||
yield_ty,
|
||||
self.local_decls,
|
||||
self.arg_count,
|
||||
self.upvar_decls,
|
||||
self.fn_span
|
||||
Mir::new(
|
||||
self.cfg.basic_blocks,
|
||||
self.source_scopes,
|
||||
ClearCrossCrate::Set(self.source_scope_local_data),
|
||||
IndexVec::new(),
|
||||
yield_ty,
|
||||
self.local_decls,
|
||||
self.arg_count,
|
||||
self.upvar_decls,
|
||||
self.fn_span,
|
||||
self.hir.control_flow_destroyed(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -372,6 +372,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
// FIXME(eddyb) use logical ops in constants when
|
||||
// they can handle that kind of control-flow.
|
||||
(hir::BinOpKind::And, hir::Constness::Const) => {
|
||||
cx.control_flow_destroyed.push((
|
||||
op.span,
|
||||
"`&&` operator".into(),
|
||||
));
|
||||
ExprKind::Binary {
|
||||
op: BinOp::BitAnd,
|
||||
lhs: lhs.to_ref(),
|
||||
@ -379,6 +383,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
(hir::BinOpKind::Or, hir::Constness::Const) => {
|
||||
cx.control_flow_destroyed.push((
|
||||
op.span,
|
||||
"`||` operator".into(),
|
||||
));
|
||||
ExprKind::Binary {
|
||||
op: BinOp::BitOr,
|
||||
lhs: lhs.to_ref(),
|
||||
|
@ -56,6 +56,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
|
||||
/// True if this constant/function needs overflow checks.
|
||||
check_overflow: bool,
|
||||
|
||||
/// See field with the same name on `Mir`
|
||||
control_flow_destroyed: Vec<(Span, String)>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
@ -96,9 +99,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
constness,
|
||||
body_owner_kind,
|
||||
check_overflow,
|
||||
control_flow_destroyed: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn control_flow_destroyed(self) -> Vec<(Span, String)> {
|
||||
self.control_flow_destroyed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
|
@ -219,7 +219,8 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
local_decls_for_sig(&sig, span),
|
||||
sig.inputs().len(),
|
||||
vec![],
|
||||
span
|
||||
span,
|
||||
vec![],
|
||||
);
|
||||
|
||||
if let Some(..) = ty {
|
||||
@ -396,7 +397,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
self.local_decls,
|
||||
self.sig.inputs().len(),
|
||||
vec![],
|
||||
self.span
|
||||
self.span,
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
@ -844,7 +846,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
local_decls,
|
||||
sig.inputs().len(),
|
||||
vec![],
|
||||
span
|
||||
span,
|
||||
vec![],
|
||||
);
|
||||
if let Abi::RustCall = sig.abi {
|
||||
mir.spread_arg = Some(Local::new(sig.inputs().len()));
|
||||
@ -921,6 +924,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
local_decls,
|
||||
sig.inputs().len(),
|
||||
vec![],
|
||||
span
|
||||
span,
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
@ -412,7 +412,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
||||
initial_locals,
|
||||
0,
|
||||
vec![],
|
||||
mir.span
|
||||
mir.span,
|
||||
vec![],
|
||||
),
|
||||
tcx,
|
||||
source: mir,
|
||||
|
@ -553,7 +553,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
this.super_place(place, context, location);
|
||||
match proj.elem {
|
||||
ProjectionElem::Deref => {
|
||||
this.add(Qualif::NOT_CONST);
|
||||
if context.is_mutating_use() {
|
||||
// `not_const` errors out in const contexts
|
||||
this.not_const()
|
||||
} else {
|
||||
// just make sure this doesn't get promoted
|
||||
this.add(Qualif::NOT_CONST);
|
||||
}
|
||||
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
|
||||
match this.mode {
|
||||
Mode::Fn => {},
|
||||
@ -1178,7 +1184,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
if self.mir.local_kind(index) == LocalKind::Var &&
|
||||
self.const_fn_arg_vars.insert(index) &&
|
||||
!self.tcx.features().const_let {
|
||||
|
||||
// Direct use of an argument is permitted.
|
||||
match *rvalue {
|
||||
Rvalue::Use(Operand::Copy(Place::Local(local))) |
|
||||
@ -1189,7 +1194,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
if self.qualif.contains(Qualif::FN_ARGUMENT) {
|
||||
let decl = &self.mir.local_decls[index];
|
||||
@ -1348,6 +1352,37 @@ impl MirPass for QualifyAndPromoteConstants {
|
||||
// Do the actual promotion, now that we know what's viable.
|
||||
promote_consts::promote_candidates(mir, tcx, temps, candidates);
|
||||
} else {
|
||||
if !mir.control_flow_destroyed.is_empty() {
|
||||
let mut locals = mir.vars_iter();
|
||||
if let Some(local) = locals.next() {
|
||||
let span = mir.local_decls[local].source_info.span;
|
||||
let mut error = tcx.sess.struct_span_err(
|
||||
span,
|
||||
&format!(
|
||||
"new features like let bindings are not permitted in {}s \
|
||||
which also use short circuiting operators",
|
||||
mode,
|
||||
),
|
||||
);
|
||||
for (span, kind) in mir.control_flow_destroyed.iter() {
|
||||
error.span_note(
|
||||
*span,
|
||||
&format!("use of {} here does not actually short circuit due to \
|
||||
the const evaluator presently not being able to do control flow. \
|
||||
See https://github.com/rust-lang/rust/issues/49146 for more \
|
||||
information.", kind),
|
||||
);
|
||||
}
|
||||
for local in locals {
|
||||
let span = mir.local_decls[local].source_info.span;
|
||||
error.span_note(
|
||||
span,
|
||||
"more locals defined here",
|
||||
);
|
||||
}
|
||||
error.emit();
|
||||
}
|
||||
}
|
||||
let promoted_temps = if mode == Mode::Const {
|
||||
// Already computed by `mir_const_qualif`.
|
||||
const_promoted_temps.unwrap()
|
||||
|
@ -230,7 +230,7 @@ fn check_statement(
|
||||
check_rvalue(tcx, mir, rval, span)
|
||||
}
|
||||
|
||||
StatementKind::FakeRead(..) => Err((span, "match in const fn is unstable".into())),
|
||||
StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span, PlaceMode::Read),
|
||||
|
||||
// just an assignment
|
||||
StatementKind::SetDiscriminant { .. } => Ok(()),
|
||||
|
@ -8,14 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_fn, const_let)]
|
||||
|
||||
const X : usize = 2;
|
||||
|
||||
const fn f(x: usize) -> usize {
|
||||
let mut sum = 0;
|
||||
//~^ let bindings in constant functions are unstable
|
||||
//~| statements in constant functions are unstable
|
||||
for i in 0..x {
|
||||
//~^ ERROR E0015
|
||||
//~| ERROR E0019
|
||||
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
// test that certain things are disallowed in constant functions
|
||||
|
||||
#![feature(const_fn, const_let)]
|
||||
|
||||
// no destructuring
|
||||
const fn i((
|
||||
a,
|
||||
b
|
||||
): (u32, u32)) -> u32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -24,7 +24,7 @@ unsafe impl Sync for Foo {}
|
||||
static FOO: Foo = Foo(UnsafeCell::new(42));
|
||||
|
||||
static BAR: () = unsafe {
|
||||
*FOO.0.get() = 5; //~ ERROR could not evaluate static initializer
|
||||
*FOO.0.get() = 5; //~ ERROR contains unimplemented expression type
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,9 +1,9 @@
|
||||
error[E0080]: could not evaluate static initializer
|
||||
error[E0019]: static contains unimplemented expression type
|
||||
--> $DIR/assign-to-static-within-other-static-2.rs:27:5
|
||||
|
|
||||
LL | *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer
|
||||
| ^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer
|
||||
LL | *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
For more information about this error, try `rustc --explain E0019`.
|
||||
|
@ -27,9 +27,7 @@ fn foo() {}
|
||||
|
||||
static BAR: () = unsafe {
|
||||
*FOO.0.get() = 5;
|
||||
// we do not error on the above access, because that is not detectable statically. Instead,
|
||||
// const evaluation will error when trying to evaluate it. Due to the error below, we never even
|
||||
// attempt to const evaluate `BAR`, so we don't see the error
|
||||
//~^ contains unimplemented expression
|
||||
|
||||
foo();
|
||||
//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
|
@ -1,9 +1,16 @@
|
||||
error[E0019]: static contains unimplemented expression type
|
||||
--> $DIR/mod-static-with-const-fn.rs:29:5
|
||||
|
|
||||
LL | *FOO.0.get() = 5;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||
--> $DIR/mod-static-with-const-fn.rs:34:5
|
||||
--> $DIR/mod-static-with-const-fn.rs:32:5
|
||||
|
|
||||
LL | foo();
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0015`.
|
||||
Some errors occurred: E0015, E0019.
|
||||
For more information about an error, try `rustc --explain E0015`.
|
||||
|
@ -37,15 +37,13 @@ const fn get_Y_addr() -> &'static u32 {
|
||||
}
|
||||
|
||||
const fn get() -> u32 {
|
||||
let x = 22;
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR statements in constant functions are unstable
|
||||
let y = 44;
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR statements in constant functions are unstable
|
||||
let x = 22; //~ ERROR let bindings in constant functions are unstable
|
||||
//~^ ERROR statements in constant functions
|
||||
let y = 44; //~ ERROR let bindings in constant functions are unstable
|
||||
//~^ ERROR statements in constant functions
|
||||
x + y
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR let bindings in constant functions are unstable
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR let bindings in constant functions are unstable
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -19,7 +19,7 @@ LL | &Y
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:40:13
|
||||
|
|
||||
LL | let x = 22;
|
||||
LL | let x = 22; //~ ERROR let bindings in constant functions are unstable
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
@ -27,29 +27,29 @@ LL | let x = 22;
|
||||
error[E0658]: statements in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:40:13
|
||||
|
|
||||
LL | let x = 22;
|
||||
LL | let x = 22; //~ ERROR let bindings in constant functions are unstable
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:43:13
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:42:13
|
||||
|
|
||||
LL | let y = 44;
|
||||
LL | let y = 44; //~ ERROR let bindings in constant functions are unstable
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:43:13
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:42:13
|
||||
|
|
||||
LL | let y = 44;
|
||||
LL | let y = 44; //~ ERROR let bindings in constant functions are unstable
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:46:5
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:44:5
|
||||
|
|
||||
LL | x + y
|
||||
| ^
|
||||
@ -57,7 +57,7 @@ LL | x + y
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:46:9
|
||||
--> $DIR/const-fn-not-safe-for-const.rs:44:9
|
||||
|
|
||||
LL | x + y
|
||||
| ^
|
||||
|
@ -8,6 +8,7 @@ struct S {
|
||||
impl S {
|
||||
const fn foo(&mut self, x: u32) {
|
||||
self.state = x;
|
||||
//~^ contains unimplemented expression
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
error[E0019]: constant function contains unimplemented expression type
|
||||
--> $DIR/const_let_assign3.rs:10:9
|
||||
|
|
||||
LL | self.state = x;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error[E0017]: references in constants may only refer to immutable values
|
||||
--> $DIR/const_let_assign3.rs:16:5
|
||||
--> $DIR/const_let_assign3.rs:17:5
|
||||
|
|
||||
LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values
|
||||
| ^ constants require immutable values
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0017`.
|
||||
Some errors occurred: E0017, E0019.
|
||||
For more information about an error, try `rustc --explain E0017`.
|
||||
|
470
src/test/ui/consts/const_let_eq.rs
Normal file
470
src/test/ui/consts/const_let_eq.rs
Normal file
@ -0,0 +1,470 @@
|
||||
#![feature(const_let, const_fn)]
|
||||
|
||||
// run-pass
|
||||
|
||||
struct Foo<T>(T);
|
||||
struct Bar<T> { x: T }
|
||||
struct W(u32);
|
||||
struct A { a: u32 }
|
||||
|
||||
const fn basics((a,): (u32,)) -> u32 {
|
||||
// Deferred assignment:
|
||||
let b: u32;
|
||||
b = a + 1;
|
||||
|
||||
// Immediate assignment:
|
||||
let c: u32 = b + 1;
|
||||
|
||||
// Mutables:
|
||||
let mut d: u32 = c + 1;
|
||||
d = d + 1;
|
||||
// +4 so far.
|
||||
|
||||
// No effect statements work:
|
||||
; ;
|
||||
1;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [0];
|
||||
arr[0] = 1;
|
||||
d = d + arr[0];
|
||||
// +5
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(0);
|
||||
let mut bar: Bar<u32> = Bar { x: 0 };
|
||||
foo.0 = 1;
|
||||
bar.x = 1;
|
||||
d = d + foo.0 + bar.x;
|
||||
// +7
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(0)];
|
||||
arr[0].0 = 1;
|
||||
d = d + arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }];
|
||||
arr[0].x = 1;
|
||||
d = d + arr[0].x;
|
||||
// +9
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([0]);
|
||||
(arr.0)[0] = 1;
|
||||
d = d + (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [0] };
|
||||
arr.x[0] = 1;
|
||||
d = d + arr.x[0];
|
||||
// +11
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn add_assign(W(a): W) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a + 1;
|
||||
d += 1;
|
||||
// +2 so far.
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [0];
|
||||
arr[0] += 1;
|
||||
d += arr[0];
|
||||
// +3
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(0);
|
||||
let mut bar: Bar<u32> = Bar { x: 0 };
|
||||
foo.0 += 1;
|
||||
bar.x += 1;
|
||||
d += foo.0 + bar.x;
|
||||
// +5
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(0)];
|
||||
arr[0].0 += 1;
|
||||
d += arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }];
|
||||
arr[0].x += 1;
|
||||
d += arr[0].x;
|
||||
// +7
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([0]);
|
||||
(arr.0)[0] += 1;
|
||||
d += (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [0] };
|
||||
arr.x[0] += 1;
|
||||
d += arr.x[0];
|
||||
// +9
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn mul_assign(A { a }: A) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a + 1;
|
||||
d *= 2;
|
||||
// 2^1 * (a + 1)
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [1];
|
||||
arr[0] *= 2;
|
||||
d *= arr[0];
|
||||
// 2^2 * (a + 1)
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(1);
|
||||
let mut bar: Bar<u32> = Bar { x: 1 };
|
||||
foo.0 *= 2;
|
||||
bar.x *= 2;
|
||||
d *= foo.0 + bar.x;
|
||||
// 2^4 * (a + 1)
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(1)];
|
||||
arr[0].0 *= 2;
|
||||
d *= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }];
|
||||
arr[0].x *= 2;
|
||||
d *= arr[0].x;
|
||||
// 2^6 * (a + 1)
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([1]);
|
||||
(arr.0)[0] *= 2;
|
||||
d *= (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [1] };
|
||||
arr.x[0] *= 2;
|
||||
d *= arr.x[0];
|
||||
// 2^8 * (a + 1)
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn div_assign(a: [u32; 1]) -> u32 {
|
||||
let a = a[0];
|
||||
// Mutables:
|
||||
let mut d: u32 = 1024 * a;
|
||||
d /= 2;
|
||||
// 512
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [4];
|
||||
arr[0] /= 2;
|
||||
d /= arr[0];
|
||||
// 256
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(4);
|
||||
let mut bar: Bar<u32> = Bar { x: 4 };
|
||||
foo.0 /= 2;
|
||||
bar.x /= 2;
|
||||
d /= foo.0;
|
||||
d /= bar.x;
|
||||
// 64
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(4)];
|
||||
arr[0].0 /= 2;
|
||||
d /= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 4 }];
|
||||
arr[0].x /= 2;
|
||||
d /= arr[0].x;
|
||||
// 16
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([4]);
|
||||
(arr.0)[0] /= 2;
|
||||
d /= (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [4] };
|
||||
arr.x[0] /= 2;
|
||||
d /= arr.x[0];
|
||||
// 4
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn rem_assign(W(a): W) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d %= 10;
|
||||
d += 10;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [3];
|
||||
arr[0] %= 2;
|
||||
d %= 9 + arr[0];
|
||||
d += 10;
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(5);
|
||||
let mut bar: Bar<u32> = Bar { x: 7 };
|
||||
foo.0 %= 2;
|
||||
bar.x %= 2;
|
||||
d %= 8 + foo.0 + bar.x;
|
||||
d += 10;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(4)];
|
||||
arr[0].0 %= 3;
|
||||
d %= 9 + arr[0].0;
|
||||
d += 10;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 7 }];
|
||||
arr[0].x %= 3;
|
||||
d %= 9 + arr[0].x;
|
||||
d += 10;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([6]);
|
||||
(arr.0)[0] %= 5;
|
||||
d %= 9 + (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [11] };
|
||||
arr.x[0] %= 5;
|
||||
d %= 9 + arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn sub_assign(W(a): W) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d -= 1;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [2];
|
||||
arr[0] -= 1;
|
||||
d -= arr[0];
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(2);
|
||||
let mut bar: Bar<u32> = Bar { x: 2 };
|
||||
foo.0 -= 1;
|
||||
bar.x -= 1;
|
||||
d -= foo.0 + bar.x;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(2)];
|
||||
arr[0].0 -= 1;
|
||||
d -= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }];
|
||||
arr[0].x -= 1;
|
||||
d -= arr[0].x;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([2]);
|
||||
(arr.0)[0] -= 1;
|
||||
d -= (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [2] };
|
||||
arr.x[0] -= 1;
|
||||
d -= arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn shl_assign(W(a): W) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d <<= 1; // 10
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [1];
|
||||
arr[0] <<= 1;
|
||||
d <<= arr[0]; // 10 << 2
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(1);
|
||||
let mut bar: Bar<u32> = Bar { x: 1 };
|
||||
foo.0 <<= 1;
|
||||
bar.x <<= 1;
|
||||
d <<= foo.0 + bar.x; // 1000 << 4
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(1)];
|
||||
arr[0].0 <<= 1;
|
||||
d <<= arr[0].0; // 1000_0000 << 2
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }];
|
||||
arr[0].x <<= 1;
|
||||
d <<= arr[0].x; // 1000_0000_00 << 2
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([1]);
|
||||
(arr.0)[0] <<= 1;
|
||||
d <<= (arr.0)[0]; // 1000_0000_0000 << 2
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [1] };
|
||||
arr.x[0] <<= 1;
|
||||
d <<= arr.x[0]; // 1000_0000_0000_00 << 2
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn shr_assign(W(a): W) -> u32 {
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d >>= 1; // /= 2
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [2];
|
||||
arr[0] >>= 1;
|
||||
d >>= arr[0]; // /= 4
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(2);
|
||||
let mut bar: Bar<u32> = Bar { x: 2 };
|
||||
foo.0 >>= 1;
|
||||
bar.x >>= 1;
|
||||
d >>= foo.0 + bar.x; // /= 16
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(2)];
|
||||
arr[0].0 >>= 1;
|
||||
d >>= arr[0].0; // /= 32
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }];
|
||||
arr[0].x >>= 1;
|
||||
d >>= arr[0].x; // /= 64
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([2]);
|
||||
(arr.0)[0] >>= 1;
|
||||
d >>= (arr.0)[0]; // /= 128
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [2] };
|
||||
arr.x[0] >>= 1;
|
||||
d >>= arr.x[0]; // /= 256
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn bit_and_assign(W(a): W) -> u32 {
|
||||
let f = 0b1111_1111_1111_1111;
|
||||
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d &= 0b1111_1111_1111_1110;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [f];
|
||||
arr[0] &= 0b1111_1111_1111_1101;
|
||||
d &= arr[0];
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(f);
|
||||
let mut bar: Bar<u32> = Bar { x: f };
|
||||
foo.0 &= 0b1111_1111_1111_0111;
|
||||
bar.x &= 0b1111_1111_1101_1111;
|
||||
d &= foo.0 & bar.x;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(f)];
|
||||
arr[0].0 &= 0b1111_1110_1111_1111;
|
||||
d &= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: f }];
|
||||
arr[0].x &= 0b1111_1101_1111_1111;
|
||||
d &= arr[0].x;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([f]);
|
||||
(arr.0)[0] &= 0b1011_1111_1111_1111;
|
||||
d &= (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [f] };
|
||||
arr.x[0] &= 0b0111_1111_1111_1111;
|
||||
d &= arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn bit_or_assign(W(a): W) -> u32 {
|
||||
let f = 0b0000_0000_0000_0000;
|
||||
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d |= 0b0000_0000_0000_0001;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [f];
|
||||
arr[0] |= 0b0000_0000_0000_1001;
|
||||
d |= arr[0];
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(f);
|
||||
let mut bar: Bar<u32> = Bar { x: f };
|
||||
foo.0 |= 0b0000_0000_0001_0000;
|
||||
bar.x |= 0b0000_0000_0100_0000;
|
||||
d |= foo.0 | bar.x;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(f)];
|
||||
arr[0].0 |= 0b0000_0001_0000_0000;
|
||||
d |= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: f }];
|
||||
arr[0].x |= 0b0000_0010_0000_0000;
|
||||
d |= arr[0].x;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([f]);
|
||||
(arr.0)[0] |= 0b1000_0000_0000_0000;
|
||||
d |= (arr.0)[0]; // /= 128
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [f] };
|
||||
arr.x[0] |= 0b1100_0000_0000_0000;
|
||||
d |= arr.x[0]; // /= 256
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn bit_xor_assign(W(a): W) -> u32 {
|
||||
let f = 0b0000_0000_0000_0000;
|
||||
|
||||
// Mutables:
|
||||
let mut d: u32 = a;
|
||||
d ^= 0b0000_0000_0000_0001;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [u32; 1] = [f];
|
||||
arr[0] ^= 0b0000_0000_0000_0010;
|
||||
d ^= arr[0];
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<u32> = Foo(f);
|
||||
let mut bar: Bar<u32> = Bar { x: f };
|
||||
foo.0 ^= 0b0000_0000_0001_0000;
|
||||
bar.x ^= 0b0000_0000_1000_0000;
|
||||
d ^= foo.0 ^ bar.x;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<u32>; 1] = [Foo(f)];
|
||||
arr[0].0 ^= 0b0000_0001_0000_0000;
|
||||
d ^= arr[0].0;
|
||||
let mut arr: [Bar<u32>; 1] = [Bar { x: f }];
|
||||
arr[0].x ^= 0b0000_0010_0000_0000;
|
||||
d ^= arr[0].x;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[u32; 1]> = Foo([f]);
|
||||
(arr.0)[0] ^= 0b0100_0000_0000_0000;
|
||||
d ^= (arr.0)[0];
|
||||
let mut arr: Bar<[u32; 1]> = Bar { x: [f] };
|
||||
arr.x[0] ^= 0b1000_0000_0000_0000;
|
||||
d ^= arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($c:ident, $e:expr, $r:expr) => {
|
||||
const $c: u32 = $e;
|
||||
assert_eq!($c, $r);
|
||||
assert_eq!($e, $r);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test!(BASICS, basics((2,)), 13);
|
||||
test!(ADD, add_assign(W(1)), 10);
|
||||
test!(MUL, mul_assign(A { a: 0 }), 256);
|
||||
test!(DIV, div_assign([1]), 4);
|
||||
test!(REM, rem_assign(W(5)), 5);
|
||||
test!(SUB, sub_assign(W(8)), 0);
|
||||
test!(SHL, shl_assign(W(1)), 0b1000_0000_0000_0000);
|
||||
test!(SHR, shr_assign(W(256)), 1);
|
||||
test!(AND, bit_and_assign(W(0b1011_1111_1111_1111_1111)), 0b0011_1100_1101_0100);
|
||||
test!(OR, bit_or_assign(W(0b1011_0000_0000_0000)), 0b1111_0011_0101_1001);
|
||||
test!(XOR, bit_xor_assign(W(0b0000_0000_0000_0000)), 0b1100_0011_1001_0011);
|
||||
}
|
279
src/test/ui/consts/const_let_eq_float.rs
Normal file
279
src/test/ui/consts/const_let_eq_float.rs
Normal file
@ -0,0 +1,279 @@
|
||||
// compile-pass
|
||||
|
||||
#![feature(const_let, const_fn)]
|
||||
|
||||
struct Foo<T>(T);
|
||||
struct Bar<T> { x: T }
|
||||
struct W(f32);
|
||||
struct A { a: f32 }
|
||||
|
||||
const fn basics((a,): (f32,)) -> f32 {
|
||||
// Deferred assignment:
|
||||
let b: f32;
|
||||
b = a + 1.0;
|
||||
|
||||
// Immediate assignment:
|
||||
let c: f32 = b + 1.0;
|
||||
|
||||
// Mutables:
|
||||
let mut d: f32 = c + 1.0;
|
||||
d = d + 1.0;
|
||||
// +4 so far.
|
||||
|
||||
// No effect statements work:
|
||||
; ;
|
||||
1;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [0.0];
|
||||
arr[0] = 1.0;
|
||||
d = d + arr[0];
|
||||
// +5
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(0.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 0.0 };
|
||||
foo.0 = 1.0;
|
||||
bar.x = 1.0;
|
||||
d = d + foo.0 + bar.x;
|
||||
// +7
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(0.0)];
|
||||
arr[0].0 = 1.0;
|
||||
d = d + arr[0].0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }];
|
||||
arr[0].x = 1.0;
|
||||
d = d + arr[0].x;
|
||||
// +9
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([0.0]);
|
||||
(arr.0)[0] = 1.0;
|
||||
d = d + (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] };
|
||||
arr.x[0] = 1.0;
|
||||
d = d + arr.x[0];
|
||||
// +11
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn add_assign(W(a): W) -> f32 {
|
||||
// Mutables:
|
||||
let mut d: f32 = a + 1.0;
|
||||
d += 1.0;
|
||||
// +2 so far.
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [0.0];
|
||||
arr[0] += 1.0;
|
||||
d += arr[0];
|
||||
// +3
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(0.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 0.0 };
|
||||
foo.0 += 1.0;
|
||||
bar.x += 1.0;
|
||||
d += foo.0 + bar.x;
|
||||
// +5
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(0.0)];
|
||||
arr[0].0 += 1.0;
|
||||
d += arr[0].0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }];
|
||||
arr[0].x += 1.0;
|
||||
d += arr[0].x;
|
||||
// +7
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([0.0]);
|
||||
(arr.0)[0] += 1.0;
|
||||
d += (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] };
|
||||
arr.x[0] += 1.0;
|
||||
d += arr.x[0];
|
||||
// +9
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn mul_assign(A { a }: A) -> f32 {
|
||||
// Mutables:
|
||||
let mut d: f32 = a + 1.0;
|
||||
d *= 2.0;
|
||||
// 2^1 * (a + 1)
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [1.0];
|
||||
arr[0] *= 2.0;
|
||||
d *= arr[0];
|
||||
// 2^2 * (a + 1)
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(1.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 1.0 };
|
||||
foo.0 *= 2.0;
|
||||
bar.x *= 2.0;
|
||||
d *= foo.0 + bar.x;
|
||||
// 2^4 * (a + 1)
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(1.0)];
|
||||
arr[0].0 *= 2.0;
|
||||
d *= arr[0].0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 1.0 }];
|
||||
arr[0].x *= 2.0;
|
||||
d *= arr[0].x;
|
||||
// 2^6 * (a + 1)
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([1.0]);
|
||||
(arr.0)[0] *= 2.0;
|
||||
d *= (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [1.0] };
|
||||
arr.x[0] *= 2.0;
|
||||
d *= arr.x[0];
|
||||
// 2^8 * (a + 1)
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn div_assign(a: [f32; 1]) -> f32 {
|
||||
let a = a[0];
|
||||
// Mutables:
|
||||
let mut d: f32 = 1024.0 * a;
|
||||
d /= 2.0;
|
||||
// 512
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [4.0];
|
||||
arr[0] /= 2.0;
|
||||
d /= arr[0];
|
||||
// 256
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(4.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 4.0 };
|
||||
foo.0 /= 2.0;
|
||||
bar.x /= 2.0;
|
||||
d /= foo.0;
|
||||
d /= bar.x;
|
||||
// 64
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(4.0)];
|
||||
arr[0].0 /= 2.0;
|
||||
d /= arr[0].0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 4.0 }];
|
||||
arr[0].x /= 2.0;
|
||||
d /= arr[0].x;
|
||||
// 16
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([4.0]);
|
||||
(arr.0)[0] /= 2.0;
|
||||
d /= (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [4.0] };
|
||||
arr.x[0] /= 2.0;
|
||||
d /= arr.x[0];
|
||||
// 4
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn rem_assign(W(a): W) -> f32 {
|
||||
// Mutables:
|
||||
let mut d: f32 = a;
|
||||
d %= 10.0;
|
||||
d += 10.0;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [3.0];
|
||||
arr[0] %= 2.0;
|
||||
d %= 9.0 + arr[0];
|
||||
d += 10.0;
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(5.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 7.0 };
|
||||
foo.0 %= 2.0;
|
||||
bar.x %= 2.0;
|
||||
d %= 8.0 + foo.0 + bar.x;
|
||||
d += 10.0;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(4.0)];
|
||||
arr[0].0 %= 3.0;
|
||||
d %= 9.0 + arr[0].0;
|
||||
d += 10.0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 7.0 }];
|
||||
arr[0].x %= 3.0;
|
||||
d %= 9.0 + arr[0].x;
|
||||
d += 10.0;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([6.0]);
|
||||
(arr.0)[0] %= 5.0;
|
||||
d %= 9.0 + (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [11.0] };
|
||||
arr.x[0] %= 5.0;
|
||||
d %= 9.0 + arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
const fn sub_assign(W(a): W) -> f32 {
|
||||
// Mutables:
|
||||
let mut d: f32 = a;
|
||||
d -= 1.0;
|
||||
|
||||
// Array projection
|
||||
let mut arr: [f32; 1] = [2.0];
|
||||
arr[0] -= 1.0;
|
||||
d -= arr[0];
|
||||
|
||||
// Field projection:
|
||||
let mut foo: Foo<f32> = Foo(2.0);
|
||||
let mut bar: Bar<f32> = Bar { x: 2.0 };
|
||||
foo.0 -= 1.0;
|
||||
bar.x -= 1.0;
|
||||
d -= foo.0 + bar.x;
|
||||
|
||||
// Array + Field projection:
|
||||
let mut arr: [Foo<f32>; 1] = [Foo(2.0)];
|
||||
arr[0].0 -= 1.0;
|
||||
d -= arr[0].0;
|
||||
let mut arr: [Bar<f32>; 1] = [Bar { x: 2.0 }];
|
||||
arr[0].x -= 1.0;
|
||||
d -= arr[0].x;
|
||||
|
||||
// Field + Array projection:
|
||||
let mut arr: Foo<[f32; 1]> = Foo([2.0]);
|
||||
(arr.0)[0] -= 1.0;
|
||||
d -= (arr.0)[0];
|
||||
let mut arr: Bar<[f32; 1]> = Bar { x: [2.0] };
|
||||
arr.x[0] -= 1.0;
|
||||
d -= arr.x[0];
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($c:ident, $e:expr, $r:expr) => {
|
||||
const $c: f32 = $e;
|
||||
assert_eq!($c, $r);
|
||||
assert_eq!($e, $r);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test!(BASICS, basics((2.0,)), 13.0);
|
||||
test!(ADD, add_assign(W(1.0)), 10.0);
|
||||
test!(MUL, mul_assign(A { a: 0.0 }), 256.0);
|
||||
test!(DIV, div_assign([1.0]), 4.0);
|
||||
test!(REM, rem_assign(W(5.0)), 5.0);
|
||||
test!(SUB, sub_assign(W(8.0)), 0.0);
|
||||
}
|
16
src/test/ui/consts/const_short_circuit.rs
Normal file
16
src/test/ui/consts/const_short_circuit.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![feature(underscore_const_names, const_let)]
|
||||
|
||||
const _: bool = false && false;
|
||||
const _: bool = true && false;
|
||||
const _: bool = {
|
||||
let mut x = true && false;
|
||||
//~^ ERROR new features like let bindings are not permitted
|
||||
x
|
||||
};
|
||||
const _: bool = {
|
||||
let x = true && false;
|
||||
//~^ ERROR new features like let bindings are not permitted
|
||||
x
|
||||
};
|
||||
|
||||
fn main() {}
|
26
src/test/ui/consts/const_short_circuit.stderr
Normal file
26
src/test/ui/consts/const_short_circuit.stderr
Normal file
@ -0,0 +1,26 @@
|
||||
error: new features like let bindings are not permitted in constants which also use short circuiting operators
|
||||
--> $DIR/const_short_circuit.rs:6:9
|
||||
|
|
||||
LL | let mut x = true && false;
|
||||
| ^^^^^
|
||||
|
|
||||
note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information.
|
||||
--> $DIR/const_short_circuit.rs:6:22
|
||||
|
|
||||
LL | let mut x = true && false;
|
||||
| ^^
|
||||
|
||||
error: new features like let bindings are not permitted in constants which also use short circuiting operators
|
||||
--> $DIR/const_short_circuit.rs:11:9
|
||||
|
|
||||
LL | let x = true && false;
|
||||
| ^
|
||||
|
|
||||
note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information.
|
||||
--> $DIR/const_short_circuit.rs:11:18
|
||||
|
|
||||
LL | let x = true && false;
|
||||
| ^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
|
||||
error: local variables in const fn are unstable
|
||||
--> $DIR/min_const_fn.rs:109:34
|
||||
|
|
||||
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
|
||||
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn
|
||||
| ^
|
||||
|
||||
error: `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
|
@ -106,7 +106,7 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize }
|
||||
const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
|
||||
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
|
||||
const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
|
||||
const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn
|
||||
const fn foo36(a: bool, b: bool) -> bool { a && b }
|
||||
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
const fn foo37(a: bool, b: bool) -> bool { a || b }
|
||||
|
@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
|
||||
error: local variables in const fn are unstable
|
||||
--> $DIR/min_const_fn.rs:109:34
|
||||
|
|
||||
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable
|
||||
LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn
|
||||
| ^
|
||||
|
||||
error: `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
|
17
src/test/ui/consts/min_const_fn/mutable_borrow.rs
Normal file
17
src/test/ui/consts/min_const_fn/mutable_borrow.rs
Normal file
@ -0,0 +1,17 @@
|
||||
const fn mutable_ref_in_const() -> u8 {
|
||||
let mut a = 0; //~ ERROR local variables in const fn
|
||||
let b = &mut a;
|
||||
*b
|
||||
}
|
||||
|
||||
struct X;
|
||||
|
||||
impl X {
|
||||
const fn inherent_mutable_ref_in_const() -> u8 {
|
||||
let mut a = 0; //~ ERROR local variables in const fn
|
||||
let b = &mut a;
|
||||
*b
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
14
src/test/ui/consts/min_const_fn/mutable_borrow.stderr
Normal file
14
src/test/ui/consts/min_const_fn/mutable_borrow.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error: local variables in const fn are unstable
|
||||
--> $DIR/mutable_borrow.rs:2:9
|
||||
|
|
||||
LL | let mut a = 0; //~ ERROR local variables in const fn
|
||||
| ^^^^^
|
||||
|
||||
error: local variables in const fn are unstable
|
||||
--> $DIR/mutable_borrow.rs:11:13
|
||||
|
|
||||
LL | let mut a = 0; //~ ERROR local variables in const fn
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -7,6 +7,7 @@ const FOO: &u32 = {
|
||||
{
|
||||
let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
|
||||
unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
|
||||
//~^ contains unimplemented expression
|
||||
}
|
||||
&{a}
|
||||
};
|
||||
|
@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values
|
||||
LL | let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values
|
||||
| ^^^^^^ constants require immutable values
|
||||
|
||||
error[E0019]: constant contains unimplemented expression type
|
||||
--> $DIR/projection_qualif.rs:9:18
|
||||
|
|
||||
LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants
|
||||
| ^^^^^^
|
||||
|
||||
error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911)
|
||||
--> $DIR/projection_qualif.rs:9:18
|
||||
|
|
||||
@ -12,7 +18,7 @@ LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constant
|
||||
|
|
||||
= help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors occurred: E0017, E0658.
|
||||
Some errors occurred: E0017, E0019, E0658.
|
||||
For more information about an error, try `rustc --explain E0017`.
|
||||
|
@ -2,6 +2,14 @@ enum Foo {
|
||||
Prob,
|
||||
}
|
||||
|
||||
const FOO: u32 = match Foo::Prob {
|
||||
Foo::Prob => 42, //~ ERROR unimplemented expression type
|
||||
};
|
||||
|
||||
const BAR: u32 = match Foo::Prob {
|
||||
x => 42, //~ ERROR unimplemented expression type
|
||||
};
|
||||
|
||||
impl Foo {
|
||||
pub const fn as_val(&self) -> u8 {
|
||||
use self::Foo::*;
|
||||
|
@ -1,8 +1,21 @@
|
||||
error[E0019]: constant contains unimplemented expression type
|
||||
--> $DIR/single_variant_match_ice.rs:6:5
|
||||
|
|
||||
LL | Foo::Prob => 42, //~ ERROR unimplemented expression type
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0019]: constant contains unimplemented expression type
|
||||
--> $DIR/single_variant_match_ice.rs:10:5
|
||||
|
|
||||
LL | x => 42, //~ ERROR unimplemented expression type
|
||||
| ^
|
||||
|
||||
error: `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
--> $DIR/single_variant_match_ice.rs:10:13
|
||||
--> $DIR/single_variant_match_ice.rs:18:13
|
||||
|
|
||||
LL | Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0019`.
|
||||
|
@ -10,13 +10,22 @@
|
||||
|
||||
// Test use of const let without feature gate.
|
||||
|
||||
#![feature(const_fn)]
|
||||
|
||||
const fn foo() -> usize {
|
||||
const FOO: usize = {
|
||||
//~^ ERROR statements in constants are unstable
|
||||
//~| ERROR: let bindings in constants are unstable
|
||||
let x = 42;
|
||||
//~^ ERROR statements in constant functions are unstable
|
||||
//~| ERROR: let bindings in constant functions are unstable
|
||||
//~^ ERROR statements in constants are unstable
|
||||
//~| ERROR: let bindings in constants are unstable
|
||||
42
|
||||
}
|
||||
};
|
||||
|
||||
static BAR: usize = {
|
||||
//~^ ERROR statements in statics are unstable
|
||||
//~| ERROR: let bindings in statics are unstable
|
||||
let x = 42;
|
||||
//~^ ERROR statements in statics are unstable
|
||||
//~| ERROR: let bindings in statics are unstable
|
||||
42
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
error[E0658]: let bindings in constants are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:16:13
|
||||
|
|
||||
LL | let x = 42;
|
||||
@ -6,7 +6,7 @@ LL | let x = 42;
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in constant functions are unstable (see issue #48821)
|
||||
error[E0658]: statements in constants are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:16:13
|
||||
|
|
||||
LL | let x = 42;
|
||||
@ -14,6 +14,78 @@ LL | let x = 42;
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0658]: let bindings in constants are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:13:1
|
||||
|
|
||||
LL | / const FOO: usize = {
|
||||
LL | | //~^ ERROR statements in constants are unstable
|
||||
LL | | //~| ERROR: let bindings in constants are unstable
|
||||
LL | | let x = 42;
|
||||
... |
|
||||
LL | | 42
|
||||
LL | | };
|
||||
| |__^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in constants are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:13:1
|
||||
|
|
||||
LL | / const FOO: usize = {
|
||||
LL | | //~^ ERROR statements in constants are unstable
|
||||
LL | | //~| ERROR: let bindings in constants are unstable
|
||||
LL | | let x = 42;
|
||||
... |
|
||||
LL | | 42
|
||||
LL | | };
|
||||
| |__^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: let bindings in statics are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:25:13
|
||||
|
|
||||
LL | let x = 42;
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in statics are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:25:13
|
||||
|
|
||||
LL | let x = 42;
|
||||
| ^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: let bindings in statics are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:22:1
|
||||
|
|
||||
LL | / static BAR: usize = {
|
||||
LL | | //~^ ERROR statements in statics are unstable
|
||||
LL | | //~| ERROR: let bindings in statics are unstable
|
||||
LL | | let x = 42;
|
||||
... |
|
||||
LL | | 42
|
||||
LL | | };
|
||||
| |__^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in statics are unstable (see issue #48821)
|
||||
--> $DIR/feature-gate-const_let.rs:22:1
|
||||
|
|
||||
LL | / static BAR: usize = {
|
||||
LL | | //~^ ERROR statements in statics are unstable
|
||||
LL | | //~| ERROR: let bindings in statics are unstable
|
||||
LL | | let x = 42;
|
||||
... |
|
||||
LL | | 42
|
||||
LL | | };
|
||||
| |__^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -8,15 +8,9 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(const_fn)]
|
||||
|
||||
const fn x() {
|
||||
let t = true;
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR statements in constant functions are unstable
|
||||
let t = true; //~ ERROR local variables in const fn
|
||||
let x = || t;
|
||||
//~^ ERROR let bindings in constant functions are unstable
|
||||
//~| ERROR statements in constant functions are unstable
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,35 +1,8 @@
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/issue-37550.rs:14:13
|
||||
error: local variables in const fn are unstable
|
||||
--> $DIR/issue-37550.rs:12:9
|
||||
|
|
||||
LL | let t = true;
|
||||
| ^^^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
LL | let t = true; //~ ERROR local variables in const fn
|
||||
| ^
|
||||
|
||||
error[E0658]: statements in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/issue-37550.rs:14:13
|
||||
|
|
||||
LL | let t = true;
|
||||
| ^^^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
error: aborting due to previous error
|
||||
|
||||
error[E0658]: let bindings in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/issue-37550.rs:17:13
|
||||
|
|
||||
LL | let x = || t;
|
||||
| ^^^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: statements in constant functions are unstable (see issue #48821)
|
||||
--> $DIR/issue-37550.rs:17:13
|
||||
|
|
||||
LL | let x = || t;
|
||||
| ^^^^
|
||||
|
|
||||
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
Loading…
Reference in New Issue
Block a user