Skip to content

Commit 83c3b7f

Browse files
committed
Auto merge of rust-lang#30930 - oli-obk:fix/30887, r=arielb1
this makes sure the checks run before typeck (which might use the constant or const function to calculate an array length) and gives prettier error messages in case of for loops and such (since they aren't expanded yet). fixes rust-lang#30887 r? @pnkfelix
2 parents 3c49053 + 1471d93 commit 83c3b7f

15 files changed

+310
-72
lines changed

mk/crates.mk

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ TARGET_CRATES := libc std flate arena term \
5757
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
5858
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
5959
rustc_data_structures rustc_front rustc_platform_intrinsics \
60-
rustc_plugin rustc_metadata
60+
rustc_plugin rustc_metadata rustc_passes
6161
HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros
6262
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
6363

@@ -97,11 +97,12 @@ DEPS_rustc_data_structures := std log serialize
9797
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
9898
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
9999
rustc_trans rustc_privacy rustc_lint rustc_front rustc_plugin \
100-
rustc_metadata syntax_ext
100+
rustc_metadata syntax_ext rustc_passes
101101
DEPS_rustc_front := std syntax log serialize
102102
DEPS_rustc_lint := rustc log syntax
103103
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
104104
DEPS_rustc_metadata := rustc rustc_front syntax rbml
105+
DEPS_rustc_passes := syntax rustc core
105106
DEPS_rustc_mir := rustc rustc_front syntax
106107
DEPS_rustc_resolve := arena rustc rustc_front log syntax
107108
DEPS_rustc_platform_intrinsics := rustc rustc_llvm

src/librustc/diagnostics.rs

-34
Original file line numberDiff line numberDiff line change
@@ -316,21 +316,6 @@ See [RFC 911] for more details on the design of `const fn`s.
316316
[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
317317
"##,
318318

319-
E0016: r##"
320-
Blocks in constants may only contain items (such as constant, function
321-
definition, etc...) and a tail expression. Example:
322-
323-
```
324-
const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
325-
```
326-
327-
To avoid it, you have to replace the non-item object:
328-
329-
```
330-
const FOO: i32 = { const X : i32 = 0; X };
331-
```
332-
"##,
333-
334319
E0017: r##"
335320
References in statics and constants may only refer to immutable values. Example:
336321
@@ -422,24 +407,6 @@ const X: i32 = 42 / 0;
422407
```
423408
"##,
424409

425-
E0022: r##"
426-
Constant functions are not allowed to mutate anything. Thus, binding to an
427-
argument with a mutable pattern is not allowed. For example,
428-
429-
```
430-
const fn foo(mut x: u8) {
431-
// do stuff
432-
}
433-
```
434-
435-
is bad because the function body may not mutate `x`.
436-
437-
Remove any mutable bindings from the argument list to fix this error. In case
438-
you need to mutate the argument, try lazily initializing a global variable
439-
instead of using a `const fn`, or refactoring the code to a functional style to
440-
avoid mutation if possible.
441-
"##,
442-
443410
E0030: r##"
444411
When matching against a range, the compiler verifies that the range is
445412
non-empty. Range patterns include both end-points, so this is equivalent to
@@ -2358,7 +2325,6 @@ register_diagnostics! {
23582325
E0316, // nested quantification of lifetimes
23592326
E0453, // overruled by outer forbid
23602327
E0471, // constant evaluation error: ..
2361-
E0472, // asm! is unsupported on this target
23622328
E0473, // dereference of reference outside its lifetime
23632329
E0474, // captured variable `..` does not outlive the enclosing closure
23642330
E0475, // index of slice outside its lifetime

src/librustc/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ pub mod middle {
102102
pub mod check_static_recursion;
103103
pub mod check_loop;
104104
pub mod check_match;
105-
pub mod check_no_asm;
106105
pub mod check_rvalues;
107106
pub mod const_eval;
108107
pub mod cstore;

src/librustc/middle/check_const.rs

+7-26
Original file line numberDiff line numberDiff line change
@@ -175,21 +175,6 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
175175
_ => Mode::Var
176176
};
177177

178-
// Ensure the arguments are simple, not mutable/by-ref or patterns.
179-
if mode == Mode::ConstFn {
180-
for arg in &fd.inputs {
181-
match arg.pat.node {
182-
hir::PatWild => {}
183-
hir::PatIdent(hir::BindByValue(hir::MutImmutable), _, None) => {}
184-
_ => {
185-
span_err!(self.tcx.sess, arg.pat.span, E0022,
186-
"arguments of constant functions can only \
187-
be immutable by-value bindings");
188-
}
189-
}
190-
}
191-
}
192-
193178
let qualif = self.with_mode(mode, |this| {
194179
this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
195180
intravisit::walk_fn(this, fk, fd, b, s);
@@ -397,24 +382,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
397382
fn visit_block(&mut self, block: &hir::Block) {
398383
// Check all statements in the block
399384
for stmt in &block.stmts {
400-
let span = match stmt.node {
385+
match stmt.node {
401386
hir::StmtDecl(ref decl, _) => {
402387
match decl.node {
403-
hir::DeclLocal(_) => decl.span,
404-
388+
hir::DeclLocal(_) => {},
405389
// Item statements are allowed
406390
hir::DeclItem(_) => continue
407391
}
408392
}
409-
hir::StmtExpr(ref expr, _) => expr.span,
410-
hir::StmtSemi(ref semi, _) => semi.span,
411-
};
412-
self.add_qualif(ConstQualif::NOT_CONST);
413-
if self.mode != Mode::Var {
414-
span_err!(self.tcx.sess, span, E0016,
415-
"blocks in {}s are limited to items and \
416-
tail expressions", self.msg());
393+
hir::StmtExpr(_, _) => {},
394+
hir::StmtSemi(_, _) => {},
417395
}
396+
self.add_qualif(ConstQualif::NOT_CONST);
397+
// anything else should have been caught by check_const_fn
398+
assert_eq!(self.mode, Mode::Var);
418399
}
419400
intravisit::walk_block(self, block);
420401
}

src/librustc_driver/driver.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
632632

633633
time(time_passes,
634634
"checking for inline asm in case the target doesn't support it",
635-
|| middle::check_no_asm::check_crate(sess, &krate));
635+
|| ::rustc_passes::no_asm::check_crate(sess, &krate));
636636

637637
// One final feature gating of the true AST that gets compiled
638638
// later, to make sure we've got everything (e.g. configuration
@@ -647,6 +647,10 @@ pub fn phase_2_configure_and_expand(sess: &Session,
647647
sess.abort_if_errors();
648648
});
649649

650+
time(time_passes,
651+
"const fn bodies and arguments",
652+
|| ::rustc_passes::const_fn::check_crate(sess, &krate));
653+
650654
if sess.opts.debugging_opts.input_stats {
651655
println!("Post-expansion node count: {}", count_nodes(&krate));
652656
}

src/librustc_driver/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern crate libc;
3838
extern crate rustc;
3939
extern crate rustc_back;
4040
extern crate rustc_borrowck;
41+
extern crate rustc_passes;
4142
extern crate rustc_front;
4243
extern crate rustc_lint;
4344
extern crate rustc_plugin;

src/librustc_passes/const_fn.rs

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Verifies that const fn arguments are immutable by value bindings
12+
//! and the const fn body doesn't contain any statements
13+
14+
use rustc::session::Session;
15+
16+
use syntax::ast;
17+
use syntax::visit::{self, Visitor, FnKind};
18+
use syntax::codemap::Span;
19+
20+
pub fn check_crate(sess: &Session, krate: &ast::Crate) {
21+
visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate);
22+
sess.abort_if_errors();
23+
}
24+
25+
struct CheckConstFn<'a> {
26+
sess: &'a Session,
27+
}
28+
29+
struct CheckBlock<'a> {
30+
sess: &'a Session,
31+
kind: &'static str,
32+
}
33+
34+
impl<'a, 'v> Visitor<'v> for CheckBlock<'a> {
35+
fn visit_block(&mut self, block: &'v ast::Block) {
36+
check_block(&self.sess, block, self.kind);
37+
CheckConstFn{ sess: self.sess}.visit_block(block);
38+
}
39+
fn visit_expr(&mut self, e: &'v ast::Expr) {
40+
if let ast::ExprClosure(..) = e.node {
41+
CheckConstFn{ sess: self.sess}.visit_expr(e);
42+
} else {
43+
visit::walk_expr(self, e);
44+
}
45+
}
46+
fn visit_item(&mut self, _i: &'v ast::Item) { panic!("should be handled in CheckConstFn") }
47+
fn visit_fn(&mut self,
48+
_fk: FnKind<'v>,
49+
_fd: &'v ast::FnDecl,
50+
_b: &'v ast::Block,
51+
_s: Span,
52+
_fn_id: ast::NodeId) { panic!("should be handled in CheckConstFn") }
53+
}
54+
55+
fn check_block(sess: &Session, b: &ast::Block, kind: &'static str) {
56+
// Check all statements in the block
57+
for stmt in &b.stmts {
58+
let span = match stmt.node {
59+
ast::StmtDecl(ref decl, _) => {
60+
match decl.node {
61+
ast::DeclLocal(_) => decl.span,
62+
63+
// Item statements are allowed
64+
ast::DeclItem(_) => continue,
65+
}
66+
}
67+
ast::StmtExpr(ref expr, _) => expr.span,
68+
ast::StmtSemi(ref semi, _) => semi.span,
69+
ast::StmtMac(..) => unreachable!(),
70+
};
71+
span_err!(sess, span, E0016,
72+
"blocks in {}s are limited to items and tail expressions", kind);
73+
}
74+
}
75+
76+
impl<'a, 'v> Visitor<'v> for CheckConstFn<'a> {
77+
fn visit_item(&mut self, i: &'v ast::Item) {
78+
visit::walk_item(self, i);
79+
match i.node {
80+
ast::ItemConst(_, ref e) => {
81+
CheckBlock{ sess: self.sess, kind: "constant"}.visit_expr(e)
82+
},
83+
ast::ItemStatic(_, _, ref e) => {
84+
CheckBlock{ sess: self.sess, kind: "static"}.visit_expr(e)
85+
},
86+
_ => {},
87+
}
88+
}
89+
90+
fn visit_fn(&mut self,
91+
fk: FnKind<'v>,
92+
fd: &'v ast::FnDecl,
93+
b: &'v ast::Block,
94+
s: Span,
95+
_fn_id: ast::NodeId) {
96+
visit::walk_fn(self, fk, fd, b, s);
97+
match fk {
98+
FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {},
99+
FnKind::Method(_, m, _) if m.constness == ast::Constness::Const => {},
100+
_ => return,
101+
}
102+
103+
// Ensure the arguments are simple, not mutable/by-ref or patterns.
104+
for arg in &fd.inputs {
105+
match arg.pat.node {
106+
ast::PatWild => {}
107+
ast::PatIdent(ast::BindingMode::ByValue(ast::MutImmutable), _, None) => {}
108+
_ => {
109+
span_err!(self.sess, arg.pat.span, E0022,
110+
"arguments of constant functions can only \
111+
be immutable by-value bindings");
112+
}
113+
}
114+
}
115+
check_block(&self.sess, b, "const function");
116+
}
117+
}

src/librustc_passes/diagnostics.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(non_snake_case)]
12+
13+
register_long_diagnostics! {
14+
E0016: r##"
15+
Blocks in constants may only contain items (such as constant, function
16+
definition, etc...) and a tail expression. Example:
17+
18+
```
19+
const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
20+
```
21+
22+
To avoid it, you have to replace the non-item object:
23+
24+
```
25+
const FOO: i32 = { const X : i32 = 0; X };
26+
```
27+
"##,
28+
29+
E0022: r##"
30+
Constant functions are not allowed to mutate anything. Thus, binding to an
31+
argument with a mutable pattern is not allowed. For example,
32+
33+
```
34+
const fn foo(mut x: u8) {
35+
// do stuff
36+
}
37+
```
38+
39+
is bad because the function body may not mutate `x`.
40+
41+
Remove any mutable bindings from the argument list to fix this error. In case
42+
you need to mutate the argument, try lazily initializing a global variable
43+
instead of using a `const fn`, or refactoring the code to a functional style to
44+
avoid mutation if possible.
45+
"##,
46+
}
47+
48+
register_diagnostics! {
49+
E0472, // asm! is unsupported on this target
50+
}

src/librustc_passes/lib.rs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Various checks
12+
//!
13+
//! # Note
14+
//!
15+
//! This API is completely unstable and subject to change.
16+
17+
#![crate_name = "rustc_passes"]
18+
#![unstable(feature = "rustc_private", issue = "27812")]
19+
#![crate_type = "dylib"]
20+
#![crate_type = "rlib"]
21+
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
22+
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
23+
html_root_url = "https://doc.rust-lang.org/nightly/")]
24+
25+
#![feature(rustc_diagnostic_macros)]
26+
#![feature(staged_api)]
27+
#![feature(rustc_private)]
28+
29+
extern crate core;
30+
extern crate rustc;
31+
32+
#[macro_use] extern crate syntax;
33+
34+
pub mod diagnostics;
35+
pub mod const_fn;
36+
pub mod no_asm;

src/librustc/middle/check_no_asm.rs src/librustc_passes/no_asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/// Inline asm isn't allowed on virtual ISA based targets, so we reject it
1313
/// here.
1414
15-
use session::Session;
15+
use rustc::session::Session;
1616

1717
use syntax::ast;
1818
use syntax::visit::Visitor;

0 commit comments

Comments
 (0)