mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
Priority levels
This commit is contained in:
parent
a23297f5c0
commit
5b3145574e
@ -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 @@ pub trait NonConstOp: std::fmt::Debug {
|
||||
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 @@ impl NonConstOp for MutDeref {
|
||||
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 @@ pub mod ty {
|
||||
}
|
||||
|
||||
#[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
|
||||
|
@ -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_span::{sym, Span, Symbol};
|
||||
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 @@ impl Validator<'mir, 'tcx> {
|
||||
ccx,
|
||||
qualifs: Default::default(),
|
||||
const_checking_stopped: false,
|
||||
error_emitted: false,
|
||||
secondary_errors: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,20 +236,20 @@ impl Validator<'mir, 'tcx> {
|
||||
|
||||
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 @@ impl Validator<'mir, 'tcx> {
|
||||
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 @@ impl Validator<'mir, 'tcx> {
|
||||
|
||||
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 @@ impl Validator<'mir, 'tcx> {
|
||||
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 @@ impl Validator<'mir, '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() {
|
||||
|
Loading…
Reference in New Issue
Block a user