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 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),
+ "delayed span bug triggered by #[rustc_error(delay_span_bug_from_inside_query)]"
+ );
+}
+
/// 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),
+ "fatal error triggered by #[rustc_error]"
+ );
+ }
+ }
+ }
}
}
}
pub fn provide(providers: &mut Providers<'_>) {
crate::symbol_names::provide(providers);
+ *providers = Providers {
+ trigger_delay_span_bug,
+ ..*providers
+ };
}