]> git.lizzy.rs Git - rust.git/commitdiff
Priority levels
authorDylan MacKenzie <ecstaticmorse@gmail.com>
Wed, 30 Sep 2020 00:52:12 +0000 (17:52 -0700)
committerDylan MacKenzie <ecstaticmorse@gmail.com>
Wed, 30 Sep 2020 02:20:33 +0000 (19:20 -0700)
compiler/rustc_mir/src/transform/check_consts/ops.rs
compiler/rustc_mir/src/transform/check_consts/validation.rs

index fba6d0d2f80d8d069aa0d47e1516d7460d787fc5..c08f4b0ea51b8712593a491ddd1fa27c4cd275b9 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_middle::mir;
 use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
@@ -17,6 +18,15 @@ pub enum Status {
     Forbidden,
 }
 
+#[derive(Clone, Copy)]
+pub enum DiagnosticImportance {
+    /// An operation that must be removed for const-checking to pass.
+    Primary,
+
+    /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
+    Secondary,
+}
+
 /// An operation that is not *always* allowed in a const context.
 pub trait NonConstOp: std::fmt::Debug {
     const STOPS_CONST_CHECKING: bool = false;
@@ -26,6 +36,10 @@ fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
         Status::Forbidden
     }
 
+    fn importance(&self) -> DiagnosticImportance {
+        DiagnosticImportance::Primary
+    }
+
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
@@ -318,6 +332,11 @@ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
+    fn importance(&self) -> DiagnosticImportance {
+        // Usually a side-effect of a `MutBorrow` somewhere.
+        DiagnosticImportance::Secondary
+    }
+
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
@@ -513,12 +532,21 @@ pub mod ty {
     use super::*;
 
     #[derive(Debug)]
-    pub struct MutRef;
+    pub struct MutRef(pub mir::LocalKind);
     impl NonConstOp for MutRef {
         fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
             Status::Unstable(sym::const_mut_refs)
         }
 
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
+
         fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
@@ -530,10 +558,19 @@ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<
     }
 
     #[derive(Debug)]
-    pub struct FnPtr;
+    pub struct FnPtr(pub mir::LocalKind);
     impl NonConstOp for FnPtr {
         const STOPS_CONST_CHECKING: bool = true;
 
+        fn importance(&self) -> DiagnosticImportance {
+            match self.0 {
+                mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+                mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
+                    DiagnosticImportance::Primary
+                }
+            }
+        }
+
         fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
index 4266dfb496565b8eb1fa764dc79d7b05078b7ac5..e0dd7970883211911039839cb51848429da668ff 100644 (file)
@@ -1,6 +1,6 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::{struct_span_err, Applicability, Diagnostic};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, HirId, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -15,6 +15,7 @@
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::{self, TraitEngine};
 
+use std::mem;
 use std::ops::Deref;
 
 use super::ops::{self, NonConstOp, Status};
@@ -181,6 +182,9 @@ pub struct Validator<'mir, 'tcx> {
     span: Span,
 
     const_checking_stopped: bool,
+
+    error_emitted: bool,
+    secondary_errors: Vec<Diagnostic>,
 }
 
 impl Deref for Validator<'mir, 'tcx> {
@@ -198,6 +202,8 @@ pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
             ccx,
             qualifs: Default::default(),
             const_checking_stopped: false,
+            error_emitted: false,
+            secondary_errors: Vec::new(),
         }
     }
 
@@ -230,20 +236,20 @@ pub fn check_body(&mut self) {
 
             self.check_item_predicates();
 
-            for local in &body.local_decls {
+            for (idx, local) in body.local_decls.iter_enumerated() {
                 if local.internal {
                     continue;
                 }
 
                 self.span = local.source_info.span;
-                self.check_local_or_return_ty(local.ty);
+                self.check_local_or_return_ty(local.ty, idx);
             }
 
             // impl trait is gone in MIR, so check the return type of a const fn by its signature
             // instead of the type of the return place.
             self.span = body.local_decls[RETURN_PLACE].source_info.span;
             let return_ty = tcx.fn_sig(def_id).output();
-            self.check_local_or_return_ty(return_ty.skip_binder());
+            self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
         }
 
         self.visit_body(&body);
@@ -257,6 +263,17 @@ pub fn check_body(&mut self) {
             let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
             check_return_ty_is_sync(tcx, &body, hir_id);
         }
+
+        // If we got through const-checking without emitting any "primary" errors, emit any
+        // "secondary" errors if they occurred.
+        let secondary_errors = mem::take(&mut self.secondary_errors);
+        if !self.error_emitted {
+            for error in secondary_errors {
+                self.tcx.sess.diagnostic().emit_diagnostic(&error);
+            }
+        } else {
+            assert!(self.tcx.sess.has_errors());
+        }
     }
 
     pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
@@ -301,7 +318,15 @@ pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
 
         let mut err = op.build_error(self.ccx, span);
         assert!(err.is_error());
-        err.emit();
+
+        match op.importance() {
+            ops::DiagnosticImportance::Primary => {
+                self.error_emitted = true;
+                err.emit();
+            }
+
+            ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
+        }
 
         if O::STOPS_CONST_CHECKING {
             self.const_checking_stopped = true;
@@ -316,7 +341,9 @@ fn check_static(&mut self, def_id: DefId, span: Span) {
         self.check_op_spanned(ops::StaticAccess, span)
     }
 
-    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
+    fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
+        let kind = self.body.local_kind(local);
+
         for ty in ty.walk() {
             let ty = match ty.unpack() {
                 GenericArgKind::Type(ty) => ty,
@@ -327,9 +354,9 @@ fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
             };
 
             match *ty.kind() {
-                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef),
+                ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
                 ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
-                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr),
+                ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
 
                 ty::Dynamic(preds, _) => {
                     for pred in preds.iter() {