Skip to content
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

Add ConstKind::Error and convert ErrorHandled::Reported to it. #71049

Merged
merged 4 commits into from
Apr 17, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 5 additions & 2 deletions src/librustc_codegen_ssa/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::glue;
use crate::traits::*;
use crate::MemFlags;

use rustc_errors::ErrorReported;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
Expand Down Expand Up @@ -447,8 +448,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| {
match err {
// errored or at least linted
ErrorHandled::Reported => {}
ErrorHandled::TooGeneric => bug!("codgen encountered polymorphic constant"),
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
bug!("codegen encountered polymorphic constant")
}
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_infer/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ pub fn unexpected_hidden_region_diagnostic(
// down this path which gives a decent human readable
// explanation.
//
// (*) if not, the `tainted_by_errors` flag would be set to
// true in any case, so we wouldn't be here at all.
// (*) if not, the `tainted_by_errors` field would be set to
// `Some(ErrorReported)` in any case, so we wouldn't be here at all.
note_and_explain_free_region(
tcx,
&mut err,
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_infer/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
bug!("unexpected const {:?}", ct)
}

ty::ConstKind::Param(_) | ty::ConstKind::Value(_) | ty::ConstKind::Unevaluated(..) => {}
ty::ConstKind::Param(_)
| ty::ConstKind::Value(_)
| ty::ConstKind::Unevaluated(..)
| ty::ConstKind::Error => {}
}

ct.super_fold_with(self)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_infer/infer/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
self.err = Some(FixupError::UnresolvedConst(vid));
return self.tcx().consts.err;
return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty });
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
}
ty::ConstKind::Infer(InferConst::Fresh(_)) => {
bug!("Unexpected const in full const resolver: {:?}", c);
Expand Down
57 changes: 25 additions & 32 deletions src/librustc_middle/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::ty::{self, layout, Ty};

use backtrace::Backtrace;
use rustc_data_structures::sync::Lock;
use rustc_errors::{struct_span_err, DiagnosticBuilder};
use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::definitions::DefPathData;
use rustc_macros::HashStable;
Expand All @@ -19,25 +19,16 @@ use std::{any::Any, fmt, mem};

#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
pub enum ErrorHandled {
/// Already reported a lint or an error for this evaluation.
Reported,
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
Reported(ErrorReported),
/// Already emitted a lint for this evaluation.
Linted,
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the substs didn't fully monomorphize it.
TooGeneric,
}

impl ErrorHandled {
pub fn assert_reported(self) {
match self {
ErrorHandled::Reported => {}
ErrorHandled::TooGeneric => bug!(
"MIR interpretation failed without reporting an error \
even though it was fully monomorphized"
),
}
}
}

CloneTypeFoldableImpls! {
ErrorHandled,
}
Expand Down Expand Up @@ -84,15 +75,12 @@ impl<'tcx> ConstEvalErr<'tcx> {
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
) -> Result<(), ErrorHandled> {
) -> ErrorHandled {
self.struct_generic(tcx, message, emit, None)
}

pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
match self.struct_error(tcx, message, |mut e| e.emit()) {
Ok(_) => ErrorHandled::Reported,
Err(x) => x,
}
self.struct_error(tcx, message, |mut e| e.emit())
}

pub fn report_as_lint(
Expand All @@ -102,7 +90,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
lint_root: hir::HirId,
span: Option<Span>,
) -> ErrorHandled {
match self.struct_generic(
self.struct_generic(
tcx,
message,
|mut lint: DiagnosticBuilder<'_>| {
Expand All @@ -122,10 +110,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
lint.emit();
},
Some(lint_root),
) {
Ok(_) => ErrorHandled::Reported,
Err(err) => err,
}
)
}

/// Create a diagnostic for this const eval error.
Expand All @@ -143,12 +128,14 @@ impl<'tcx> ConstEvalErr<'tcx> {
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
lint_root: Option<hir::HirId>,
) -> Result<(), ErrorHandled> {
) -> ErrorHandled {
let must_error = match self.error {
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
return Err(ErrorHandled::TooGeneric);
return ErrorHandled::TooGeneric;
}
err_inval!(TypeckError(error_reported)) => {
return ErrorHandled::Reported(error_reported);
}
err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
// We must *always* hard error on these, even if the caller wants just a lint.
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
Copy link
Contributor

@Centril Centril Apr 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this case doesn't early return so it results in Ok(_) and then report_as_lint will turn it into ErrorReported::Linted, which seems wrong?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function unfortunately became a mess over time. :/ I get the feeling we are trying to shove too many different things into one code path here.

I also do not have the slightest clue what that replace_span_with business in report_as_lint is even doing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But SizeOverflow will be a hard error even when report_as_lint is called, so always returning Linted there seems wrong, superficially.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function unfortunately became a mess over time. :/ I get the feeling we are trying to shove too many different things into one code path here.

My thoughts exactly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, so the must_error variable should be eliminated in favour of early returning here by calling report_as_error

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept must_error but replaced Result<(), ErrorHandled> in the return type with ErrorHandled, let me know if that's enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that works, too, lgtm

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoiding that boolean could have made the code cleaner... but maybe not, and anyway we can leave that to later.

_ => false,
Expand Down Expand Up @@ -183,6 +170,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
// caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>.
finish(struct_error(tcx, &err_msg), None);
ErrorHandled::Reported(ErrorReported)
} else {
// Regular case.
if let Some(lint_root) = lint_root {
Expand All @@ -200,12 +188,13 @@ impl<'tcx> ConstEvalErr<'tcx> {
tcx.span,
|lint| finish(lint.build(message), Some(err_msg)),
);
ErrorHandled::Linted
} else {
// Report as hard error.
finish(struct_error(tcx, message), Some(err_msg));
ErrorHandled::Reported(ErrorReported)
}
}
Ok(())
}
}

Expand Down Expand Up @@ -246,7 +235,9 @@ fn print_backtrace(backtrace: &mut Backtrace) {
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
match err {
ErrorHandled::Reported => err_inval!(ReferencedConstant),
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {
err_inval!(ReferencedConstant)
}
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
}
.into()
Expand Down Expand Up @@ -288,7 +279,7 @@ pub enum InvalidProgramInfo<'tcx> {
/// which already produced an error.
ReferencedConstant,
/// Abort in case type errors are reached.
TypeckError,
TypeckError(ErrorReported),
/// An error occurred during layout computation.
Layout(layout::LayoutError<'tcx>),
/// An invalid transmute happened.
Expand All @@ -301,7 +292,9 @@ impl fmt::Debug for InvalidProgramInfo<'_> {
match self {
TooGeneric => write!(f, "encountered overly generic constant"),
ReferencedConstant => write!(f, "referenced constant has errors"),
TypeckError => write!(f, "encountered constants with type errors, stopping evaluation"),
TypeckError(ErrorReported) => {
write!(f, "encountered constants with type errors, stopping evaluation")
}
Layout(ref err) => write!(f, "{}", err),
TransmuteSizeDiff(from_ty, to_ty) => write!(
f,
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_middle/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ pub struct CommonLifetimes<'tcx> {
}

pub struct CommonConsts<'tcx> {
pub err: &'tcx Const<'tcx>,
pub unit: &'tcx Const<'tcx>,
Centril marked this conversation as resolved.
Show resolved Hide resolved
}

pub struct LocalTableInContext<'a, V> {
Expand Down Expand Up @@ -410,8 +410,8 @@ pub struct TypeckTables<'tcx> {
pub used_trait_imports: Lrc<DefIdSet>,

/// If any errors occurred while type-checking this body,
/// this field will be set to `true`.
pub tainted_by_errors: bool,
/// this field will be set to `Some(ErrorReported)`.
pub tainted_by_errors: Option<ErrorReported>,

/// All the opaque types that are restricted to concrete types
/// by this function.
Expand Down Expand Up @@ -447,7 +447,7 @@ impl<'tcx> TypeckTables<'tcx> {
fru_field_types: Default::default(),
coercion_casts: Default::default(),
used_trait_imports: Lrc::new(Default::default()),
tainted_by_errors: false,
tainted_by_errors: None,
concrete_opaque_types: Default::default(),
upvar_list: Default::default(),
generator_interior_types: Default::default(),
Expand Down Expand Up @@ -858,9 +858,9 @@ impl<'tcx> CommonConsts<'tcx> {
let mk_const = |c| interners.const_.intern(c, |c| Interned(interners.arena.alloc(c))).0;

CommonConsts {
err: mk_const(ty::Const {
unit: mk_const(ty::Const {
val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::zst())),
ty: types.err,
ty: types.unit,
}),
}
}
Expand Down
10 changes: 2 additions & 8 deletions src/librustc_middle/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,7 @@ impl FlagComputation {
| &ty::Str
| &ty::Foreign(..) => {}

// You might think that we could just return Error for
// any type containing Error as a component, and get
// rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
// the exception of function types that return bot).
// But doing so caused sporadic memory corruption, and
// neither I (tjc) nor nmatsakis could figure out why,
// so we're doing it this way.
Centril marked this conversation as resolved.
Show resolved Hide resolved
&ty::Error => self.add_flags(TypeFlags::HAS_TY_ERR),
&ty::Error => self.add_flags(TypeFlags::HAS_ERROR),

&ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM);
Expand Down Expand Up @@ -239,6 +232,7 @@ impl FlagComputation {
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Value(_) => {}
ty::ConstKind::Error => self.add_flags(TypeFlags::HAS_ERROR),
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/ty/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
}
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_ERR)
self.has_type_flags(TypeFlags::HAS_ERROR)
}
fn has_param_types_or_consts(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_middle/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{self, par_iter, ParallelIterator};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
Expand Down Expand Up @@ -567,8 +568,8 @@ bitflags! {
| TypeFlags::HAS_TY_OPAQUE.bits
| TypeFlags::HAS_CT_PROJECTION.bits;

/// Is an error type reachable?
const HAS_TY_ERR = 1 << 13;
/// Is an error type/const reachable?
const HAS_ERROR = 1 << 13;

/// Does this have any region that "appears free" in the type?
/// Basically anything but [ReLateBound] and [ReErased].
Expand Down Expand Up @@ -2388,7 +2389,7 @@ impl<'tcx> AdtDef {
None
}
}
Err(ErrorHandled::Reported) => {
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {
if !expr_did.is_local() {
span_bug!(
tcx.def_span(expr_did),
Expand Down
1 change: 1 addition & 0 deletions src/librustc_middle/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,7 @@ pub trait PrettyPrinter<'tcx>:
self.pretty_print_bound_var(debruijn, bound_var)?
}
ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
ty::ConstKind::Error => p!(write("[const error]")),
};
Ok(self)
}
Expand Down
12 changes: 12 additions & 0 deletions src/librustc_middle/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,21 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
let tcx = relation.tcx();

let eagerly_eval = |x: &'tcx ty::Const<'tcx>| {
// FIXME(eddyb) this doesn't account for lifetime inference variables
// being erased by `eval`, *nor* for the polymorphic aspect of `eval`.
// That is, we could always use `eval` and it will just return the
// old value back if it doesn't succeed.
if !x.val.needs_infer() {
return x.eval(tcx, relation.param_env()).val;
}
x.val
};

// FIXME(eddyb) doesn't look like everything below checks that `a.ty == b.ty`.
// We could probably always assert it early, as `const` generic parameters
// are not allowed to depend on other generic parameters, i.e. are concrete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this temporary and won't always remain so, so let's not bake that assumption too deeply into the compiler.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already, this is nothing compared to everything else. It's only "temporary" in the sense that the first thing we stabilize won't have generic parameters in const parameter types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of the problem is we'd need to stabilize something like StructuralMatch (some deep trait, unlike StructuralPartialEq/StructuralEq), because we can't just allow unrestricted types.
But even with that also it's a PITA to implement correctly, far more so than just concrete types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I understand all of this; I'm just saying we should avoid too deep of an architectural dependence on the fact that const params can't depend on type params so that it doesn't take a year to dig out of.

// (although there could be normalization differences)

// Currently, the values that can be unified are primitive types,
// and those that derive both `PartialEq` and `Eq`, corresponding
// to structural-match types.
Expand All @@ -524,6 +533,9 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
// The caller should handle these cases!
bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
}

(ty::ConstKind::Error, _) | (_, ty::ConstKind::Error) => Ok(ty::ConstKind::Error),

(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
return Ok(a);
}
Expand Down
14 changes: 8 additions & 6 deletions src/librustc_middle/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1022,9 +1022,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
ty::ConstKind::Unevaluated(did, substs, promoted) => {
ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
}
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
*self
}
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Error => *self,
}
}

Expand All @@ -1033,9 +1034,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor),
ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
false
}
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Error => false,
}
}
}
Expand Down
Loading