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 loop label resolution around constants #52568

Merged
merged 4 commits into from
Jul 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
58 changes: 22 additions & 36 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ pub struct LoweringContext<'a> {
loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,
is_in_trait_impl: bool,
is_in_anon_const: bool,

/// What to do when we encounter either an "anonymous lifetime
/// reference". The term "anonymous" is meant to encompass both
Expand Down Expand Up @@ -231,7 +230,6 @@ pub fn lower_crate(
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_in_trait_impl: false,
is_in_anon_const: false,
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
Expand Down Expand Up @@ -970,26 +968,22 @@ impl<'a> LoweringContext<'a> {
}

fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
let target_id = if self.is_in_anon_const {
Err(hir::LoopIdError::OutsideLoopScope)
} else {
match destination {
Some((id, _)) => {
if let Def::Label(loop_id) = self.expect_full_def(id) {
Ok(self.lower_node_id(loop_id).node_id)
} else {
Err(hir::LoopIdError::UnresolvedLabel)
}
}
None => {
self.loop_scopes
.last()
.map(|innermost_loop_id| *innermost_loop_id)
.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
.into()
let target_id = match destination {
Some((id, _)) => {
if let Def::Label(loop_id) = self.expect_full_def(id) {
Ok(self.lower_node_id(loop_id).node_id)
} else {
Err(hir::LoopIdError::UnresolvedLabel)
}
}
None => {
self.loop_scopes
.last()
.map(|innermost_loop_id| *innermost_loop_id)
.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
.into()
}
};
hir::Destination {
label: self.lower_label(destination.map(|(_, label)| label)),
Expand Down Expand Up @@ -3448,22 +3442,14 @@ impl<'a> LoweringContext<'a> {
}

fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
let was_in_loop_condition = self.is_in_loop_condition;
self.is_in_loop_condition = false;
let was_in_anon_const = self.is_in_anon_const;
self.is_in_anon_const = true;

let LoweredNodeId { node_id, hir_id } = self.lower_node_id(c.id);
let anon_const = hir::AnonConst {
id: node_id,
hir_id,
body: self.lower_body(None, |this| this.lower_expr(&c.value)),
};

self.is_in_anon_const = was_in_anon_const;
self.is_in_loop_condition = was_in_loop_condition;

anon_const
self.with_new_scopes(|this| {
let LoweredNodeId { node_id, hir_id } = this.lower_node_id(c.id);
hir::AnonConst {
id: node_id,
hir_id,
body: this.lower_body(None, |this| this.lower_expr(&c.value)),
}
})
}

fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"run all passes except codegen; no output"),
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
"treat all errors that occur as bugs"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug`"),
external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
"show macro backtraces even for non-local macros"),
teach: bool = (false, parse_bool, [TRACKED],
Expand Down Expand Up @@ -3133,6 +3135,10 @@ mod tests {
opts.debugging_opts.treat_err_as_bug = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.report_delayed_bugs = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.continue_parse_after_error = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ pub fn build_session_with_codemap(
let can_emit_warnings = !(warnings_allow || cap_lints_allow);

let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
let report_delayed_bugs = sopts.debugging_opts.report_delayed_bugs;

let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;

Expand Down Expand Up @@ -1045,6 +1046,7 @@ pub fn build_session_with_codemap(
errors::HandlerFlags {
can_emit_warnings,
treat_err_as_bug,
report_delayed_bugs,
external_macro_backtrace,
..Default::default()
},
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_errors/diagnostic_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl<'a> DiagnosticBuilder<'a> {
/// locally in whichever way makes the most sense.
pub fn delay_as_bug(&mut self) {
self.level = Level::Bug;
*self.handler.delayed_span_bug.borrow_mut() = Some(self.diagnostic.clone());
self.handler.delay_as_bug(self.diagnostic.clone());
self.cancel();
}

Expand Down
32 changes: 26 additions & 6 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ pub struct Handler {
err_count: AtomicUsize,
emitter: Lock<Box<dyn Emitter + sync::Send>>,
continue_after_error: LockCell<bool>,
delayed_span_bug: Lock<Option<Diagnostic>>,
delayed_span_bugs: Lock<Vec<Diagnostic>>,

// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
// emitting the same diagnostic with extended help (`--teach`) twice, which
Expand All @@ -299,9 +299,25 @@ thread_local!(pub static TRACK_DIAGNOSTICS: Cell<fn(&Diagnostic)> =
pub struct HandlerFlags {
pub can_emit_warnings: bool,
pub treat_err_as_bug: bool,
pub report_delayed_bugs: bool,
pub external_macro_backtrace: bool,
}

impl Drop for Handler {
fn drop(&mut self) {
if self.err_count() == 0 {
let mut bugs = self.delayed_span_bugs.borrow_mut();
let has_bugs = !bugs.is_empty();
for bug in bugs.drain(..) {
DiagnosticBuilder::new_diagnostic(self, bug).emit();
}
if has_bugs {
panic!("no errors encountered even though `delay_span_bug` issued");
}
}
}
}

impl Handler {
pub fn with_tty_emitter(color_config: ColorConfig,
can_emit_warnings: bool,
Expand Down Expand Up @@ -346,7 +362,7 @@ impl Handler {
err_count: AtomicUsize::new(0),
emitter: Lock::new(e),
continue_after_error: LockCell::new(true),
delayed_span_bug: Lock::new(None),
delayed_span_bugs: Lock::new(Vec::new()),
taught_diagnostics: Lock::new(FxHashSet()),
emitted_diagnostic_codes: Lock::new(FxHashSet()),
emitted_diagnostics: Lock::new(FxHashSet()),
Expand Down Expand Up @@ -503,11 +519,18 @@ impl Handler {
}
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
if self.flags.treat_err_as_bug {
// FIXME: don't abort here if report_delayed_bugs is off
Copy link
Member

Choose a reason for hiding this comment

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

How straightforward is this to address in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh it's easy. I just didn't want to change the default behaviour in this PR. ppl might get confused and not know about the extra flag you need to get the old behaviour back

self.span_bug(sp, msg);
}
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
diagnostic.set_span(sp.into());
*self.delayed_span_bug.borrow_mut() = Some(diagnostic);
self.delay_as_bug(diagnostic);
}
fn delay_as_bug(&self, diagnostic: Diagnostic) {
if self.flags.report_delayed_bugs {
DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
}
self.delayed_span_bugs.borrow_mut().push(diagnostic);
}
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.emit(&sp.into(), msg, Bug);
Expand Down Expand Up @@ -615,9 +638,6 @@ impl Handler {

pub fn abort_if_errors(&self) {
if self.err_count() == 0 {
if let Some(bug) = self.delayed_span_bug.borrow_mut().take() {
DiagnosticBuilder::new_diagnostic(self, bug).emit();
}
return;
}
FatalError.raise();
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,9 @@ impl<'a> Resolver<'a> {
where F: FnOnce(&mut Resolver)
{
self.ribs[ValueNS].push(Rib::new(ConstantItemRibKind));
self.label_ribs.push(Rib::new(ConstantItemRibKind));
f(self);
self.label_ribs.pop();
self.ribs[ValueNS].pop();
}

Expand Down
3 changes: 0 additions & 3 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,6 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);

// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
// emit an error.
GatherLocalsVisitor { fcx: &fcx }.visit_body(body);

fcx.check_expr_coercable_to_type(&body.value, expected_type);
Expand Down
1 change: 1 addition & 0 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub fn new_handler(error_format: ErrorOutputType, codemap: Option<Lrc<codemap::C
errors::HandlerFlags {
can_emit_warnings: true,
treat_err_as_bug: false,
report_delayed_bugs: false,
external_macro_backtrace: false,
..Default::default()
},
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/const-eval/issue-52442.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2018 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.

fn main() {
[(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type
}
9 changes: 9 additions & 0 deletions src/test/ui/const-eval/issue-52442.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0019]: constant contains unimplemented expression type
--> $DIR/issue-52442.rs:12:14
|
LL | [(); { &loop { break } as *const _ as usize } ]; //~ ERROR unimplemented expression type
| ^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0019`.
18 changes: 18 additions & 0 deletions src/test/ui/const-eval/issue-52443.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2018 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.

fn main() {
[(); & { loop { continue } } ]; //~ ERROR mismatched types
[(); loop { break }]; //~ ERROR mismatched types
[(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
[(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
//~^ ERROR constant contains unimplemented expression type
//~| ERROR could not evaluate repeat length
}
51 changes: 51 additions & 0 deletions src/test/ui/const-eval/issue-52443.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
error[E0308]: mismatched types
--> $DIR/issue-52443.rs:12:10
|
LL | [(); & { loop { continue } } ]; //~ ERROR mismatched types
| ^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected usize, found reference
| help: consider removing the borrow: `{ loop { continue } }`
|
= note: expected type `usize`
found type `&_`

error[E0308]: mismatched types
--> $DIR/issue-52443.rs:13:17
|
LL | [(); loop { break }]; //~ ERROR mismatched types
| ^^^^^ expected (), found usize
|
= note: expected type `()`
found type `usize`

error[E0019]: constant contains unimplemented expression type
--> $DIR/issue-52443.rs:14:11
|
LL | [(); {while true {break}; 0}]; //~ ERROR constant contains unimplemented expression type
| ^^^^^^^^^^^^^^^^^^

error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
--> $DIR/issue-52443.rs:15:21
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^

error[E0019]: constant contains unimplemented expression type
--> $DIR/issue-52443.rs:15:21
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^

error[E0080]: could not evaluate repeat length
--> $DIR/issue-52443.rs:15:10
|
LL | [(); { for _ in 0usize.. {}; 0}]; //~ ERROR calls in constants are limited to constant functions
| ^^^^^^^^^^^--------^^^^^^^
| |
| calling non-const fn `<I as std::iter::IntoIterator><std::ops::RangeFrom<usize>>::into_iter`

error: aborting due to 6 previous errors

Some errors occurred: E0015, E0019, E0080, E0308.
For more information about an error, try `rustc --explain E0015`.