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

Rollup of 4 pull requests #116501

Merged
merged 12 commits into from
Oct 7, 2023
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
11 changes: 0 additions & 11 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,6 @@ pub(crate) fn verify_func(
}

fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
if let Err(err) =
fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
{
err.emit_err(fx.tcx);
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
// compilation should have been aborted
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
return;
}

let arg_uninhabited = fx
.mir
.args_iter()
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}

pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
// `MirUsedCollector` visited all constants before codegen began, so if we got here there
// can be no more constants that fail to evaluate.
self.monomorphize(constant.const_)
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
.expect("erroneous constant not captured by required_consts")
Expand Down
15 changes: 4 additions & 11 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,18 +209,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
caller_location: None,
};

fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
// It may seem like we should iterate over `required_consts` to ensure they all successfully
// evaluate; however, the `MirUsedCollector` already did that during the collection phase of
// monomorphization so we don't have to do it again.

// Rust post-monomorphization checks; we later rely on them.
if let Err(err) =
mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
{
err.emit_err(cx.tcx());
// This IR shouldn't ever be emitted, but let's try to guard against any of this code
// ever running.
start_bx.abort();
return;
}
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);

let memory_locals = analyze::non_ssa_locals(&fx);

Expand Down
29 changes: 18 additions & 11 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,12 +750,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
if M::POST_MONO_CHECKS {
// `ctfe_query` does some error message decoration that we want to be in effect here.
self.ctfe_query(None, |tcx| {
body.post_mono_checks(*tcx, self.param_env, |c| {
self.subst_from_current_frame_and_normalize_erasing_regions(c)
})
})?;
for &const_ in &body.required_consts {
let c =
self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| {
err.emit_note(*self.tcx);
err
})?;
}
}

// done
Expand Down Expand Up @@ -1054,14 +1056,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(())
}

/// Call a query that can return `ErrorHandled`. If `span` is `Some`, point to that span when an error occurs.
/// Call a query that can return `ErrorHandled`. Should be used for statics and other globals.
/// (`mir::Const`/`ty::Const` have `eval` methods that can be used directly instead.)
pub fn ctfe_query<T>(
&self,
span: Option<Span>,
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
) -> Result<T, ErrorHandled> {
// Use a precise span for better cycle errors.
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
query(self.tcx.at(self.cur_span())).map_err(|err| {
err.emit_note(*self.tcx);
err
})
Expand All @@ -1082,7 +1084,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
self.param_env
};
let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
let val = self.ctfe_query(|tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
self.raw_const_to_mplace(val)
}

Expand All @@ -1092,7 +1094,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?;
let const_val = val.eval(*self.tcx, self.param_env, span).map_err(|err| {
// FIXME: somehow this is reachable even when POST_MONO_CHECKS is on.
// Are we not always populating `required_consts`?
err.emit_note(*self.tcx);
err
})?;
self.const_val_to_op(const_val, val.ty(), layout)
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::type_name => Ty::new_static_str(self.tcx.tcx),
_ => bug!(),
};
let val = self.ctfe_query(None, |tcx| {
let val = self.ctfe_query(|tcx| {
tcx.const_eval_global_id(self.param_env, gid, Some(tcx.span))
})?;
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

// We don't give a span -- statics don't need that, they cannot be generic or associated.
let val = self.ctfe_query(None, |tcx| tcx.eval_static_initializer(def_id))?;
let val = self.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
(val, Some(def_id))
}
};
Expand Down
15 changes: 0 additions & 15 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,6 @@ impl ErrorHandled {
}
}

pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
match self {
&ErrorHandled::Reported(err, span) => {
if !err.is_tainted_by_errors && !span.is_dummy() {
tcx.sess.emit_err(error::ErroneousConstant { span });
}
err.error
}
&ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
span,
"encountered TooGeneric error when monomorphic data was expected",
),
}
}

pub fn emit_note(&self, tcx: TyCtxt<'_>) {
match self {
&ErrorHandled::Reported(err, span) => {
Expand Down
30 changes: 1 addition & 29 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html

use crate::mir::interpret::{AllocRange, ConstAllocation, ErrorHandled, Scalar};
use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar};
use crate::mir::visit::MirVisitable;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
Expand Down Expand Up @@ -568,34 +568,6 @@ impl<'tcx> Body<'tcx> {
pub fn is_custom_mir(&self) -> bool {
self.injection_phase.is_some()
}

/// *Must* be called once the full substitution for this body is known, to ensure that the body
/// is indeed fit for code generation or consumption more generally.
///
/// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
/// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
/// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
/// functions makes it seem like exposing the generic args is not the intended strategy.)
///
/// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
/// so we cannot just immediately ICE on TooGeneric.
///
/// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
pub fn post_mono_checks(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>,
) -> Result<(), ErrorHandled> {
// For now, the only thing we have to check is is to ensure that all the constants used in
// the body successfully evaluate.
for &const_ in &self.required_consts {
let c = normalize_const(const_.const_)?;
c.eval(tcx, param_env, Some(const_.span))?;
}

Ok(())
}
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ macro_rules! make_mir_visitor {

visit_place_fns!($($mutability)?);

/// This is called for every constant in the MIR body and every `required_consts`
/// (i.e., including consts that have been dead-code-eliminated).
fn visit_constant(
&mut self,
constant: & $($mutability)? ConstOperand<'tcx>,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,8 @@ fn collect_used_items<'tcx>(
);
}

// Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
// and abort compilation if any of them errors.
MirUsedCollector {
tcx,
body: &body,
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ parse_expected_semi_found_str = expected `;`, found `{$token}`

parse_expected_statement_after_outer_attr = expected statement after outer attribute

parse_expected_struct_field = expected one of `,`, `:`, or `{"}"}`, found `{$token}`
.label = expected one of `,`, `:`, or `{"}"}`
.ident_label = while parsing this struct field

parse_expected_trait_in_trait_impl_found_type = expected a trait, found type

parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,17 @@ pub(crate) struct ExpectedElseBlock {
pub condition_start: Span,
}

#[derive(Diagnostic)]
#[diag(parse_expected_struct_field)]
pub(crate) struct ExpectedStructField {
#[primary_span]
#[label]
pub span: Span,
pub token: Token,
#[label(parse_ident_label)]
pub ident_span: Span,
}

#[derive(Diagnostic)]
#[diag(parse_outer_attribute_not_allowed_on_if_else)]
pub(crate) struct OuterAttributeNotAllowedOnIfElse {
Expand Down
92 changes: 73 additions & 19 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2834,7 +2834,7 @@ impl<'a> Parser<'a> {
)?;
let guard = if this.eat_keyword(kw::If) {
let if_span = this.prev_token.span;
let mut cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?;
let mut cond = this.parse_match_guard_condition()?;

CondChecker { parser: this, forbid_let_reason: None }.visit_expr(&mut cond);

Expand All @@ -2860,9 +2860,9 @@ impl<'a> Parser<'a> {
{
err.span_suggestion(
this.token.span,
"try using a fat arrow here",
"use a fat arrow to start a match arm",
"=>",
Applicability::MaybeIncorrect,
Applicability::MachineApplicable,
);
err.emit();
this.bump();
Expand Down Expand Up @@ -2979,6 +2979,33 @@ impl<'a> Parser<'a> {
})
}

fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err(
|mut err| {
if self.prev_token == token::OpenDelim(Delimiter::Brace) {
let sugg_sp = self.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg = "you might have meant to start a match arm after the match guard";
if self.eat(&token::CloseDelim(Delimiter::Brace)) {
let applicability = if self.token.kind != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ".to_string(), applicability);
}
}
err
},
)
}

pub(crate) fn is_builtin(&self) -> bool {
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
}
Expand Down Expand Up @@ -3049,9 +3076,10 @@ impl<'a> Parser<'a> {
|| self.look_ahead(2, |t| t == &token::Colon)
&& (
// `{ ident: token, ` cannot start a block.
self.look_ahead(4, |t| t == &token::Comma) ||
// `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
self.look_ahead(3, |t| !t.can_begin_type())
self.look_ahead(4, |t| t == &token::Comma)
// `{ ident: ` cannot start a block unless it's a type ascription
// `ident: Type`.
|| self.look_ahead(3, |t| !t.can_begin_type())
)
)
}
Expand Down Expand Up @@ -3091,6 +3119,7 @@ impl<'a> Parser<'a> {
let mut fields = ThinVec::new();
let mut base = ast::StructRest::None;
let mut recover_async = false;
let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD);

let mut async_block_err = |e: &mut Diagnostic, span: Span| {
recover_async = true;
Expand Down Expand Up @@ -3128,6 +3157,26 @@ impl<'a> Parser<'a> {
e.span_label(pth.span, "while parsing this struct");
}

if let Some((ident, _)) = self.token.ident()
&& !self.token.is_reserved_ident()
&& self.look_ahead(1, |t| {
AssocOp::from_token(&t).is_some()
|| matches!(t.kind, token::OpenDelim(_))
|| t.kind == token::Dot
})
{
// Looks like they tried to write a shorthand, complex expression.
e.span_suggestion_verbose(
self.token.span.shrink_to_lo(),
"try naming a field",
&format!("{ident}: ", ),
Applicability::MaybeIncorrect,
);
}
if in_if_guard && close_delim == Delimiter::Brace {
return Err(e);
}

if !recover {
return Err(e);
}
Expand Down Expand Up @@ -3173,19 +3222,6 @@ impl<'a> Parser<'a> {
",",
Applicability::MachineApplicable,
);
} else if is_shorthand
&& (AssocOp::from_token(&self.token).is_some()
|| matches!(&self.token.kind, token::OpenDelim(_))
|| self.token.kind == token::Dot)
{
// Looks like they tried to write a shorthand, complex expression.
let ident = parsed_field.expect("is_shorthand implies Some").ident;
e.span_suggestion(
ident.span.shrink_to_lo(),
"try naming a field",
&format!("{ident}: "),
Applicability::HasPlaceholders,
);
}
}
if !recover {
Expand Down Expand Up @@ -3288,6 +3324,24 @@ impl<'a> Parser<'a> {

// Check if a colon exists one ahead. This means we're parsing a fieldname.
let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
// Proactively check whether parsing the field will be incorrect.
let is_wrong = this.token.is_ident()
&& !this.token.is_reserved_ident()
&& !this.look_ahead(1, |t| {
t == &token::Colon
|| t == &token::Eq
|| t == &token::Comma
|| t == &token::CloseDelim(Delimiter::Brace)
|| t == &token::CloseDelim(Delimiter::Parenthesis)
});
if is_wrong {
return Err(errors::ExpectedStructField {
span: this.look_ahead(1, |t| t.span),
ident_span: this.token.span,
token: this.look_ahead(1, |t| t.clone()),
}
.into_diagnostic(&self.sess.span_diagnostic));
}
let (ident, expr) = if is_shorthand {
// Mimic `x: x` for the `x` field shorthand.
let ident = this.parse_ident_common(false)?;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ bitflags::bitflags! {
const NO_STRUCT_LITERAL = 1 << 1;
const CONST_EXPR = 1 << 2;
const ALLOW_LET = 1 << 3;
const IN_IF_GUARD = 1 << 4;
}
}

Expand Down
Loading