Skip to content

Commit 5b31455

Browse files
Priority levels
1 parent a23297f commit 5b31455

File tree

2 files changed

+74
-10
lines changed

2 files changed

+74
-10
lines changed

compiler/rustc_mir/src/transform/check_consts/ops.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use rustc_errors::{struct_span_err, DiagnosticBuilder};
44
use rustc_hir as hir;
55
use rustc_hir::def_id::DefId;
6+
use rustc_middle::mir;
67
use rustc_session::config::nightly_options;
78
use rustc_session::parse::feature_err;
89
use rustc_span::symbol::sym;
@@ -17,6 +18,15 @@ pub enum Status {
1718
Forbidden,
1819
}
1920

21+
#[derive(Clone, Copy)]
22+
pub enum DiagnosticImportance {
23+
/// An operation that must be removed for const-checking to pass.
24+
Primary,
25+
26+
/// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
27+
Secondary,
28+
}
29+
2030
/// An operation that is not *always* allowed in a const context.
2131
pub trait NonConstOp: std::fmt::Debug {
2232
const STOPS_CONST_CHECKING: bool = false;
@@ -26,6 +36,10 @@ pub trait NonConstOp: std::fmt::Debug {
2636
Status::Forbidden
2737
}
2838

39+
fn importance(&self) -> DiagnosticImportance {
40+
DiagnosticImportance::Primary
41+
}
42+
2943
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
3044
let mut err = struct_span_err!(
3145
ccx.tcx.sess,
@@ -318,6 +332,11 @@ impl NonConstOp for MutDeref {
318332
Status::Unstable(sym::const_mut_refs)
319333
}
320334

335+
fn importance(&self) -> DiagnosticImportance {
336+
// Usually a side-effect of a `MutBorrow` somewhere.
337+
DiagnosticImportance::Secondary
338+
}
339+
321340
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
322341
feature_err(
323342
&ccx.tcx.sess.parse_sess,
@@ -513,12 +532,21 @@ pub mod ty {
513532
use super::*;
514533

515534
#[derive(Debug)]
516-
pub struct MutRef;
535+
pub struct MutRef(pub mir::LocalKind);
517536
impl NonConstOp for MutRef {
518537
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
519538
Status::Unstable(sym::const_mut_refs)
520539
}
521540

541+
fn importance(&self) -> DiagnosticImportance {
542+
match self.0 {
543+
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
544+
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
545+
DiagnosticImportance::Primary
546+
}
547+
}
548+
}
549+
522550
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
523551
feature_err(
524552
&ccx.tcx.sess.parse_sess,
@@ -530,10 +558,19 @@ pub mod ty {
530558
}
531559

532560
#[derive(Debug)]
533-
pub struct FnPtr;
561+
pub struct FnPtr(pub mir::LocalKind);
534562
impl NonConstOp for FnPtr {
535563
const STOPS_CONST_CHECKING: bool = true;
536564

565+
fn importance(&self) -> DiagnosticImportance {
566+
match self.0 {
567+
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
568+
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
569+
DiagnosticImportance::Primary
570+
}
571+
}
572+
}
573+
537574
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
538575
if ccx.const_kind() != hir::ConstContext::ConstFn {
539576
Status::Allowed

compiler/rustc_mir/src/transform/check_consts/validation.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
22
3-
use rustc_errors::{struct_span_err, Applicability};
3+
use rustc_errors::{struct_span_err, Applicability, Diagnostic};
44
use rustc_hir::def_id::{DefId, LocalDefId};
55
use rustc_hir::{self as hir, HirId, LangItem};
66
use rustc_infer::infer::TyCtxtInferExt;
@@ -15,6 +15,7 @@ use rustc_span::{sym, Span, Symbol};
1515
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
1616
use rustc_trait_selection::traits::{self, TraitEngine};
1717

18+
use std::mem;
1819
use std::ops::Deref;
1920

2021
use super::ops::{self, NonConstOp, Status};
@@ -181,6 +182,9 @@ pub struct Validator<'mir, 'tcx> {
181182
span: Span,
182183

183184
const_checking_stopped: bool,
185+
186+
error_emitted: bool,
187+
secondary_errors: Vec<Diagnostic>,
184188
}
185189

186190
impl Deref for Validator<'mir, 'tcx> {
@@ -198,6 +202,8 @@ impl Validator<'mir, 'tcx> {
198202
ccx,
199203
qualifs: Default::default(),
200204
const_checking_stopped: false,
205+
error_emitted: false,
206+
secondary_errors: Vec::new(),
201207
}
202208
}
203209

@@ -230,20 +236,20 @@ impl Validator<'mir, 'tcx> {
230236

231237
self.check_item_predicates();
232238

233-
for local in &body.local_decls {
239+
for (idx, local) in body.local_decls.iter_enumerated() {
234240
if local.internal {
235241
continue;
236242
}
237243

238244
self.span = local.source_info.span;
239-
self.check_local_or_return_ty(local.ty);
245+
self.check_local_or_return_ty(local.ty, idx);
240246
}
241247

242248
// impl trait is gone in MIR, so check the return type of a const fn by its signature
243249
// instead of the type of the return place.
244250
self.span = body.local_decls[RETURN_PLACE].source_info.span;
245251
let return_ty = tcx.fn_sig(def_id).output();
246-
self.check_local_or_return_ty(return_ty.skip_binder());
252+
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
247253
}
248254

249255
self.visit_body(&body);
@@ -257,6 +263,17 @@ impl Validator<'mir, 'tcx> {
257263
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
258264
check_return_ty_is_sync(tcx, &body, hir_id);
259265
}
266+
267+
// If we got through const-checking without emitting any "primary" errors, emit any
268+
// "secondary" errors if they occurred.
269+
let secondary_errors = mem::take(&mut self.secondary_errors);
270+
if !self.error_emitted {
271+
for error in secondary_errors {
272+
self.tcx.sess.diagnostic().emit_diagnostic(&error);
273+
}
274+
} else {
275+
assert!(self.tcx.sess.has_errors());
276+
}
260277
}
261278

262279
pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
@@ -301,7 +318,15 @@ impl Validator<'mir, 'tcx> {
301318

302319
let mut err = op.build_error(self.ccx, span);
303320
assert!(err.is_error());
304-
err.emit();
321+
322+
match op.importance() {
323+
ops::DiagnosticImportance::Primary => {
324+
self.error_emitted = true;
325+
err.emit();
326+
}
327+
328+
ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors),
329+
}
305330

306331
if O::STOPS_CONST_CHECKING {
307332
self.const_checking_stopped = true;
@@ -316,7 +341,9 @@ impl Validator<'mir, 'tcx> {
316341
self.check_op_spanned(ops::StaticAccess, span)
317342
}
318343

319-
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>) {
344+
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
345+
let kind = self.body.local_kind(local);
346+
320347
for ty in ty.walk() {
321348
let ty = match ty.unpack() {
322349
GenericArgKind::Type(ty) => ty,
@@ -327,9 +354,9 @@ impl Validator<'mir, 'tcx> {
327354
};
328355

329356
match *ty.kind() {
330-
ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef),
357+
ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)),
331358
ty::Opaque(..) => self.check_op(ops::ty::ImplTrait),
332-
ty::FnPtr(..) => self.check_op(ops::ty::FnPtr),
359+
ty::FnPtr(..) => self.check_op(ops::ty::FnPtr(kind)),
333360

334361
ty::Dynamic(preds, _) => {
335362
for pred in preds.iter() {

0 commit comments

Comments
 (0)