Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various aspects around let bindings inside const functions #56160

Merged
merged 25 commits into from
Dec 18, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4d2bed9
Stabilize `const_let` inside const functions
oli-obk Nov 22, 2018
dba5ba0
Update a test's diagnostics
oli-obk Nov 22, 2018
df2123c
Update compile-fail test
oli-obk Nov 22, 2018
52b67b1
Remove a bunch of now-unnecessary `const_let` feature gates
oli-obk Nov 23, 2018
ef38afc
Add a test for various const let features
oli-obk Nov 23, 2018
59c6c49
Also test the `const_let` feature gate in statics
oli-obk Nov 23, 2018
7ec3c10
Add tests for mutable borrows
oli-obk Nov 23, 2018
d62bcad
Allow `let` bindings everywhere
oli-obk Nov 24, 2018
507ea97
Properly name the flag for `&&` -> `&` conversion
oli-obk Nov 26, 2018
75ce28a
Show auto-applicable correction warning for short circuiting in const…
oli-obk Nov 26, 2018
d8ece18
Improve the error around short circuiting and let bindings
oli-obk Nov 26, 2018
866664c
Add a test for single variant matches
oli-obk Nov 26, 2018
8937faa
Reenable `const_let` feature gate
oli-obk Nov 26, 2018
16d2a92
Improve the diagnostic message
oli-obk Nov 26, 2018
ac47bd7
Fix a compile-fail test
oli-obk Nov 27, 2018
25d1c07
Remove unused feature gate from `libcore`
oli-obk Nov 27, 2018
172b428
Re-add accidentally deleted test
oli-obk Nov 27, 2018
42e5317
Add trailing newline
oli-obk Nov 27, 2018
9d2f97b
Test float assign ops
oli-obk Nov 27, 2018
e6e08c6
Fix rebase fallout
oli-obk Nov 30, 2018
07345f0
Undo a change that got lost in the larger refactorings
oli-obk Dec 12, 2018
2cb5e3d
Manually inline trivial function
oli-obk Dec 12, 2018
6ca2ad5
Correct documentation about `FakeRead`
oli-obk Dec 12, 2018
b678238
Properly worded diagnostic message
oli-obk Dec 18, 2018
d815e2b
Explain that lack of short circuiting support in constants is temporary
oli-obk Dec 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,8 @@ 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 aid destructuring diagnostics
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is not the correct reason. The reason we add FakeRead is documented on FakeReadCause::ForLet -- basically it is to ensure that we give errors in some cases where we generate more optimized IR (not just for diagnostics).

FakeRead(FakeReadCause, Place<'tcx>),

/// Write the discriminant for a variant to the enum Place.
Expand Down
52 changes: 7 additions & 45 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
return;
}

if self.tcx.features().const_let {
if self.const_let_allowed() {
let mut dest = dest;
let index = loop {
match dest {
Expand Down Expand Up @@ -320,6 +320,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
}
}

fn const_let_allowed(&self) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a great place for a comment =) in particular, documenting the logic behind these rules.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like:


Currently, without a feature gate, let is only allowed in const fn. With a feature gate, it can appear anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided on not doing this dual-scheme. Instead we're poisoning constants that use short circuiting operators so they can't also have let bindings.

I'll remove the function and move back to checking the feature gate directly

self.tcx.features().const_let || self.mode == Mode::ConstFn
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
}

/// Qualify a whole const, static initializer or const fn.
fn qualify_const(&mut self) -> (Qualif, Lrc<BitSet<Local>>) {
debug!("qualifying {} {:?}", self.mode, self.def_id);
Expand Down Expand Up @@ -357,7 +361,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
TerminatorKind::FalseUnwind { .. } => None,

TerminatorKind::Return => {
if !self.tcx.features().const_let {
if !self.const_let_allowed() {
// Check for unused values. This usually means
// there are extra statements in the AST.
for temp in mir.temps_iter() {
Expand Down Expand Up @@ -464,7 +468,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
LocalKind::ReturnPointer => {
self.not_const();
}
LocalKind::Var if !self.tcx.features().const_let => {
LocalKind::Var if !self.const_let_allowed() => {
if self.mode != Mode::Fn {
emit_feature_err(&self.tcx.sess.parse_sess, "const_let",
self.span, GateIssue::Language,
Expand Down Expand Up @@ -1154,48 +1158,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
debug!("visit_assign: dest={:?} rvalue={:?} location={:?}", dest, rvalue, location);
self.visit_rvalue(rvalue, location);

// Check the allowed const fn argument forms.
if let (Mode::ConstFn, &Place::Local(index)) = (self.mode, dest) {
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))) |
Rvalue::Use(Operand::Move(Place::Local(local))) => {
if self.mir.local_kind(local) == LocalKind::Arg {
return;
}
}
_ => {}
}

// Avoid a generic error for other uses of arguments.
if self.qualif.contains(Qualif::FN_ARGUMENT) {
let decl = &self.mir.local_decls[index];
let mut err = feature_err(
&self.tcx.sess.parse_sess,
"const_let",
decl.source_info.span,
GateIssue::Language,
"arguments of constant functions can only be immutable by-value bindings"
);
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("Constant functions are not allowed to mutate anything. Thus, \
binding to an argument with a mutable pattern is not allowed.");
err.note("Remove any mutable bindings from the argument list to fix this \
error. In case you need to mutate the argument, try lazily \
initializing a global variable instead of using a const fn, or \
refactoring the code to a functional style to avoid mutation if \
possible.");
}
err.emit();
return;
}
}
}

self.assign(dest, location);
}

Expand Down
19 changes: 3 additions & 16 deletions src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@ pub fn is_min_const_fn(
}
}

for local in mir.vars_iter() {
return Err((
mir.local_decls[local].source_info.span,
"local variables in const fn are unstable".into(),
));
}
for local in &mir.local_decls {
check_ty(tcx, local.ty, local.source_info.span)?;
}
Expand Down Expand Up @@ -229,7 +223,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(()),
Expand Down Expand Up @@ -270,15 +264,8 @@ fn check_place(
mode: PlaceMode,
) -> McfResult {
match place {
Place::Local(l) => match mode {
PlaceMode::Assign => match mir.local_kind(*l) {
LocalKind::Temp | LocalKind::ReturnPointer => Ok(()),
LocalKind::Arg | LocalKind::Var => {
Err((span, "assignments in const fn are unstable".into()))
}
},
PlaceMode::Read => Ok(()),
},
// assignments to locals, arguments, temporaries or the return slot are fine
Place::Local(_) => Ok(()),
// promoteds are always fine, they are essentially constants
Place::Promoted(_) => Ok(()),
Place::Static(_) => Err((span, "cannot access `static` items in const fn".into())),
Expand Down
14 changes: 2 additions & 12 deletions src/test/ui/consts/const-fn-destructuring-arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// test that certain things are disallowed in constant functions
// compile-pass

#![feature(const_fn)]

// no destructuring
const fn i((
a,
//~^ ERROR arguments of constant functions can only be immutable by-value bindings
b
//~^ ERROR arguments of constant functions can only be immutable by-value bindings
): (u32, u32)) -> u32 {
const fn i((a, b): (u32, u32)) -> u32 {
a + b
//~^ ERROR let bindings in constant functions are unstable
//~| ERROR let bindings in constant functions are unstable
}

fn main() {}
35 changes: 0 additions & 35 deletions src/test/ui/consts/const-fn-destructuring-arg.stderr

This file was deleted.

6 changes: 0 additions & 6 deletions src/test/ui/consts/const-fn-not-safe-for-const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,8 @@ 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
x + y
//~^ ERROR let bindings in constant functions are unstable
//~| ERROR let bindings in constant functions are unstable
}

fn main() {}
52 changes: 2 additions & 50 deletions src/test/ui/consts/const-fn-not-safe-for-const.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,7 @@ error[E0013]: constant functions cannot refer to statics, use a constant instead
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;
| ^^
|
= 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:40:13
|
LL | let x = 22;
| ^^
|
= 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
|
LL | let y = 44;
| ^^
|
= 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
|
LL | let y = 44;
| ^^
|
= 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
|
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
|
LL | x + y
| ^
|
= help: add #![feature(const_let)] to the crate attributes to enable

error: aborting due to 9 previous errors
error: aborting due to 3 previous errors

Some errors occurred: E0013, E0015, E0658.
Some errors occurred: E0013, E0015.
For more information about an error, try `rustc --explain E0013`.
8 changes: 1 addition & 7 deletions src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,6 @@ error: `if`, `match`, `&&` and `||` are not stable in const fn
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
| ^

error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:110:44
|
Expand Down Expand Up @@ -221,7 +215,7 @@ error: function pointers in const fn are unstable
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^

error: aborting due to 35 previous errors
error: aborting due to 34 previous errors

Some errors occurred: E0493, E0515.
For more information about an error, try `rustc --explain E0493`.
2 changes: 1 addition & 1 deletion src/test/ui/consts/min_const_fn/min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
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 }
Expand Down
8 changes: 1 addition & 7 deletions src/test/ui/consts/min_const_fn/min_const_fn.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,6 @@ error: `if`, `match`, `&&` and `||` are not stable in const fn
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
| ^

error: `if`, `match`, `&&` and `||` are not stable in const fn
--> $DIR/min_const_fn.rs:110:44
|
Expand Down Expand Up @@ -208,6 +202,6 @@ error: function pointers in const fn are unstable
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^

error: aborting due to 35 previous errors
error: aborting due to 34 previous errors

For more information about this error, try `rustc --explain E0493`.
12 changes: 6 additions & 6 deletions src/test/ui/feature-gates/feature-gate-const_let.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@

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

Centril marked this conversation as resolved.
Show resolved Hide resolved
fn main() {}
34 changes: 31 additions & 3 deletions src/test/ui/feature-gates/feature-gate-const_let.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
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;
| ^^
|
= 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;
| ^^
|
= 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: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0658`.