Skip to content

Making ICEs and test them in incremental #66060

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

Merged
merged 9 commits into from
Nov 20, 2019
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ use syntax_pos::symbol::InternedString;
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
rustc_queries! {
Other {
query trigger_delay_span_bug(key: DefId) -> () {
desc { "trigger a delay span bug" }
}
}

Other {
/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
Expand Down
32 changes: 29 additions & 3 deletions src/librustc_codegen_utils/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,52 @@ extern crate rustc;

use rustc::ty::TyCtxt;
use rustc::ty::query::Providers;
use rustc::hir::def_id::LOCAL_CRATE;
use rustc::hir::def_id::{LOCAL_CRATE, DefId};
use syntax::symbol::sym;

pub mod link;
pub mod codegen_backend;
pub mod symbol_names;
pub mod symbol_names_test;


pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: DefId) {
tcx.sess.delay_span_bug(tcx.def_span(key), "compilation successful");
}

/// check for the #[rustc_error] annotation, which forces an
/// error in codegen. This is used to write compile-fail tests
/// that actually test that compilation succeeds without
/// reporting an error.
pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
if tcx.has_attr(def_id, sym::rustc_error) {
tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful");
let attrs = &*tcx.get_attrs(def_id);
for attr in attrs {
if attr.check_name(sym::rustc_error) {
match attr.meta_item_list() {
// check if there is a #[rustc_error(delayed)]
Some(list) => {
if list.iter().any(|list_item| {
list_item.ident().map(|i| i.name) ==
Some(sym::delay_span_bug_from_inside_query)
}) {
tcx.ensure().trigger_delay_span_bug(def_id);
}
}
// bare #[rustc_error]
None => {
tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful");
}
}
}
}
}
}

pub fn provide(providers: &mut Providers<'_>) {
crate::symbol_names::provide(providers);
*providers = Providers {
trigger_delay_span_bug,
..*providers
};
}
5 changes: 4 additions & 1 deletion src/libsyntax/feature_gate/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)),
rustc_attr!(
TEST, rustc_error, Whitelisted,
template!(Word, List: "delay_span_bug_from_inside_query")
),
rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")),
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ symbols! {
default_lib_allocator,
default_type_parameter_fallback,
default_type_params,
delay_span_bug_from_inside_query,
deny,
deprecated,
deref,
Expand Down
8 changes: 8 additions & 0 deletions src/test/incremental/delayed_span_bug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// revisions: cfail1 cfail2
// should-ice
// error-pattern: compilation successful

#![feature(rustc_attrs)]

#[rustc_error(delay_span_bug_from_inside_query)]
fn main() {}
10 changes: 10 additions & 0 deletions src/tools/compiletest/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ pub struct TestProps {
// If true, `rustfix` will only apply `MachineApplicable` suggestions.
pub rustfix_only_machine_applicable: bool,
pub assembly_output: Option<String>,
// If true, the test is expected to ICE
pub should_ice: bool,
}

impl TestProps {
Expand Down Expand Up @@ -414,6 +416,7 @@ impl TestProps {
run_rustfix: false,
rustfix_only_machine_applicable: false,
assembly_output: None,
should_ice: false,
}
}

Expand Down Expand Up @@ -464,6 +467,10 @@ impl TestProps {
self.pp_exact = config.parse_pp_exact(ln, testfile);
}

if !self.should_ice {
self.should_ice = config.parse_should_ice(ln);
}

if !self.build_aux_docs {
self.build_aux_docs = config.parse_build_aux_docs(ln);
}
Expand Down Expand Up @@ -688,6 +695,9 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut dyn FnMut(&str)) {
}

impl Config {
fn parse_should_ice(&self, line: &str) -> bool {
self.parse_name_directive(line, "should-ice")
}
fn parse_error_pattern(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "error-pattern")
}
Expand Down
23 changes: 18 additions & 5 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ impl<'test> TestCx<'test> {
fn run_cfail_test(&self) {
let proc_res = self.compile_test();
self.check_if_test_should_compile(&proc_res);
self.check_no_compiler_crash(&proc_res);
self.check_no_compiler_crash(&proc_res, self.props.should_ice);

let output_to_check = self.get_output(&proc_res);
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
Expand All @@ -395,6 +395,12 @@ impl<'test> TestCx<'test> {
} else {
self.check_error_patterns(&output_to_check, &proc_res);
}
if self.props.should_ice {
match proc_res.status.code() {
Some(101) => (),
_ => self.fatal("expected ICE"),
}
}

self.check_forbid_output(&output_to_check, &proc_res);
}
Expand Down Expand Up @@ -428,7 +434,12 @@ impl<'test> TestCx<'test> {
}

fn check_correct_failure_status(&self, proc_res: &ProcRes) {
let expected_status = Some(self.props.failure_status);
let expected_status =
if self.props.should_ice {
Some(101)
} else {
Some(self.props.failure_status)
};
let received_status = proc_res.status.code();

if expected_status != received_status {
Expand Down Expand Up @@ -1402,9 +1413,11 @@ impl<'test> TestCx<'test> {
}
}

fn check_no_compiler_crash(&self, proc_res: &ProcRes) {
fn check_no_compiler_crash(&self, proc_res: &ProcRes, should_ice: bool) {
match proc_res.status.code() {
Some(101) => self.fatal_proc_rec("compiler encountered internal error", proc_res),
Some(101) if !should_ice => {
self.fatal_proc_rec("compiler encountered internal error", proc_res)
}
None => self.fatal_proc_rec("compiler terminated by signal", proc_res),
_ => (),
}
Expand Down Expand Up @@ -2518,7 +2531,7 @@ impl<'test> TestCx<'test> {
self.fatal_proc_rec("compilation failed!", &proc_res);
}

self.check_no_compiler_crash(&proc_res);
self.check_no_compiler_crash(&proc_res, self.props.should_ice);

const PREFIX: &'static str = "MONO_ITEM ";
const CGU_MARKER: &'static str = "@@";
Expand Down