Auto merge of #116501 - workingjubilee:rollup-fpzov6m, r=workingjubilee
Rollup of 4 pull requests Successful merges: - #116277 (dont call mir.post_mono_checks in codegen) - #116400 (Detect missing `=>` after match guard during parsing) - #116458 (Properly export function defined in test which uses global_asm!()) - #116500 (Add tvOS to target_os for register_dtor) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
93b6a36568
41 changed files with 266 additions and 124 deletions
|
@ -250,17 +250,6 @@ pub(crate) fn verify_func(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
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
|
let arg_uninhabited = fx
|
||||||
.mir
|
.mir
|
||||||
.args_iter()
|
.args_iter()
|
||||||
|
|
|
@ -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> {
|
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_)
|
self.monomorphize(constant.const_)
|
||||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||||
.expect("erroneous constant not captured by required_consts")
|
.expect("erroneous constant not captured by required_consts")
|
||||||
|
|
|
@ -209,18 +209,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||||
caller_location: None,
|
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.
|
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let memory_locals = analyze::non_ssa_locals(&fx);
|
let memory_locals = analyze::non_ssa_locals(&fx);
|
||||||
|
|
||||||
|
|
|
@ -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).
|
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||||
if M::POST_MONO_CHECKS {
|
if M::POST_MONO_CHECKS {
|
||||||
// `ctfe_query` does some error message decoration that we want to be in effect here.
|
for &const_ in &body.required_consts {
|
||||||
self.ctfe_query(None, |tcx| {
|
let c =
|
||||||
body.post_mono_checks(*tcx, self.param_env, |c| {
|
self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?;
|
||||||
self.subst_from_current_frame_and_normalize_erasing_regions(c)
|
c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| {
|
||||||
})
|
err.emit_note(*self.tcx);
|
||||||
})?;
|
err
|
||||||
|
})?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// done
|
// done
|
||||||
|
@ -1054,14 +1056,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(())
|
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>(
|
pub fn ctfe_query<T>(
|
||||||
&self,
|
&self,
|
||||||
span: Option<Span>,
|
|
||||||
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
|
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
|
||||||
) -> Result<T, ErrorHandled> {
|
) -> Result<T, ErrorHandled> {
|
||||||
// Use a precise span for better cycle errors.
|
// 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.emit_note(*self.tcx);
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
|
@ -1082,7 +1084,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
} else {
|
} else {
|
||||||
self.param_env
|
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)
|
self.raw_const_to_mplace(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1092,7 +1094,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
layout: Option<TyAndLayout<'tcx>>,
|
layout: Option<TyAndLayout<'tcx>>,
|
||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
) -> 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)
|
self.const_val_to_op(const_val, val.ty(), layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
sym::type_name => Ty::new_static_str(self.tcx.tcx),
|
||||||
_ => bug!(),
|
_ => 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))
|
tcx.const_eval_global_id(self.param_env, gid, Some(tcx.span))
|
||||||
})?;
|
})?;
|
||||||
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
|
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
|
||||||
|
|
|
@ -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.
|
// 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))
|
(val, Some(def_id))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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<'_>) {
|
pub fn emit_note(&self, tcx: TyCtxt<'_>) {
|
||||||
match self {
|
match self {
|
||||||
&ErrorHandled::Reported(err, span) => {
|
&ErrorHandled::Reported(err, span) => {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
|
//! [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::mir::visit::MirVisitable;
|
||||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||||
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
|
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
|
||||||
|
@ -568,34 +568,6 @@ impl<'tcx> Body<'tcx> {
|
||||||
pub fn is_custom_mir(&self) -> bool {
|
pub fn is_custom_mir(&self) -> bool {
|
||||||
self.injection_phase.is_some()
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
|
|
@ -184,6 +184,8 @@ macro_rules! make_mir_visitor {
|
||||||
|
|
||||||
visit_place_fns!($($mutability)?);
|
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(
|
fn visit_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
constant: & $($mutability)? ConstOperand<'tcx>,
|
constant: & $($mutability)? ConstOperand<'tcx>,
|
||||||
|
|
|
@ -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 {
|
MirUsedCollector {
|
||||||
tcx,
|
tcx,
|
||||||
body: &body,
|
body: &body,
|
||||||
|
|
|
@ -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_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_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
|
parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
|
||||||
|
|
|
@ -430,6 +430,17 @@ pub(crate) struct ExpectedElseBlock {
|
||||||
pub condition_start: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(parse_outer_attribute_not_allowed_on_if_else)]
|
#[diag(parse_outer_attribute_not_allowed_on_if_else)]
|
||||||
pub(crate) struct OuterAttributeNotAllowedOnIfElse {
|
pub(crate) struct OuterAttributeNotAllowedOnIfElse {
|
||||||
|
|
|
@ -2834,7 +2834,7 @@ impl<'a> Parser<'a> {
|
||||||
)?;
|
)?;
|
||||||
let guard = if this.eat_keyword(kw::If) {
|
let guard = if this.eat_keyword(kw::If) {
|
||||||
let if_span = this.prev_token.span;
|
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);
|
CondChecker { parser: this, forbid_let_reason: None }.visit_expr(&mut cond);
|
||||||
|
|
||||||
|
@ -2860,9 +2860,9 @@ impl<'a> Parser<'a> {
|
||||||
{
|
{
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
this.token.span,
|
this.token.span,
|
||||||
"try using a fat arrow here",
|
"use a fat arrow to start a match arm",
|
||||||
"=>",
|
"=>",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
this.bump();
|
this.bump();
|
||||||
|
@ -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 {
|
pub(crate) fn is_builtin(&self) -> bool {
|
||||||
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
|
self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
|
||||||
}
|
}
|
||||||
|
@ -3049,9 +3076,10 @@ impl<'a> Parser<'a> {
|
||||||
|| self.look_ahead(2, |t| t == &token::Colon)
|
|| self.look_ahead(2, |t| t == &token::Colon)
|
||||||
&& (
|
&& (
|
||||||
// `{ ident: token, ` cannot start a block.
|
// `{ ident: token, ` cannot start a block.
|
||||||
self.look_ahead(4, |t| t == &token::Comma) ||
|
self.look_ahead(4, |t| t == &token::Comma)
|
||||||
// `{ ident: ` cannot start a block unless it's a type ascription `ident: Type`.
|
// `{ ident: ` cannot start a block unless it's a type ascription
|
||||||
self.look_ahead(3, |t| !t.can_begin_type())
|
// `ident: Type`.
|
||||||
|
|| self.look_ahead(3, |t| !t.can_begin_type())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -3091,6 +3119,7 @@ impl<'a> Parser<'a> {
|
||||||
let mut fields = ThinVec::new();
|
let mut fields = ThinVec::new();
|
||||||
let mut base = ast::StructRest::None;
|
let mut base = ast::StructRest::None;
|
||||||
let mut recover_async = false;
|
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| {
|
let mut async_block_err = |e: &mut Diagnostic, span: Span| {
|
||||||
recover_async = true;
|
recover_async = true;
|
||||||
|
@ -3128,6 +3157,26 @@ impl<'a> Parser<'a> {
|
||||||
e.span_label(pth.span, "while parsing this struct");
|
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 {
|
if !recover {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
|
@ -3173,19 +3222,6 @@ impl<'a> Parser<'a> {
|
||||||
",",
|
",",
|
||||||
Applicability::MachineApplicable,
|
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 {
|
if !recover {
|
||||||
|
@ -3288,6 +3324,24 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
// Check if a colon exists one ahead. This means we're parsing a fieldname.
|
// 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);
|
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 {
|
let (ident, expr) = if is_shorthand {
|
||||||
// Mimic `x: x` for the `x` field shorthand.
|
// Mimic `x: x` for the `x` field shorthand.
|
||||||
let ident = this.parse_ident_common(false)?;
|
let ident = this.parse_ident_common(false)?;
|
||||||
|
|
|
@ -52,6 +52,7 @@ bitflags::bitflags! {
|
||||||
const NO_STRUCT_LITERAL = 1 << 1;
|
const NO_STRUCT_LITERAL = 1 << 1;
|
||||||
const CONST_EXPR = 1 << 2;
|
const CONST_EXPR = 1 << 2;
|
||||||
const ALLOW_LET = 1 << 3;
|
const ALLOW_LET = 1 << 3;
|
||||||
|
const IN_IF_GUARD = 1 << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||||
// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
|
// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
|
||||||
// thread. thread_local dtors are pushed to the DTOR list without calling
|
// thread. thread_local dtors are pushed to the DTOR list without calling
|
||||||
// _tlv_atexit.
|
// _tlv_atexit.
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
|
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))]
|
||||||
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
|
||||||
use crate::cell::Cell;
|
use crate::cell::Cell;
|
||||||
use crate::mem;
|
use crate::mem;
|
||||||
|
|
|
@ -803,8 +803,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
if tcx.is_foreign_item(def_id) {
|
if tcx.is_foreign_item(def_id) {
|
||||||
throw_unsup_format!("foreign thread-local statics are not supported");
|
throw_unsup_format!("foreign thread-local statics are not supported");
|
||||||
}
|
}
|
||||||
// We don't give a span -- statics don't need that, they cannot be generic or associated.
|
let allocation = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||||
let allocation = this.ctfe_query(None, |tcx| tcx.eval_static_initializer(def_id))?;
|
|
||||||
let mut allocation = allocation.inner().clone();
|
let mut allocation = allocation.inner().clone();
|
||||||
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
||||||
allocation.mutability = Mutability::Mut;
|
allocation.mutability = Mutability::Mut;
|
||||||
|
|
|
@ -11,7 +11,14 @@ use std::arch::global_asm;
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn my_func() {}
|
fn my_func() {}
|
||||||
|
|
||||||
global_asm!("call_foobar: jmp {}", sym foobar);
|
global_asm!("
|
||||||
|
.globl call_foobar
|
||||||
|
.type call_foobar,@function
|
||||||
|
.pushsection .text.call_foobar,\"ax\",@progbits
|
||||||
|
call_foobar: jmp {}
|
||||||
|
.size call_foobar, .-call_foobar
|
||||||
|
.popsection
|
||||||
|
", sym foobar);
|
||||||
|
|
||||||
fn foobar() {}
|
fn foobar() {}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,6 @@ fn main(){
|
||||||
//~^ ERROR expected identifier, found keyword `return`
|
//~^ ERROR expected identifier, found keyword `return`
|
||||||
//~| NOTE expected identifier, found keyword
|
//~| NOTE expected identifier, found keyword
|
||||||
}
|
}
|
||||||
//~^ NOTE expected one of `.`, `=>`, `?`, or an operator
|
|
||||||
_ => {}
|
_ => {}
|
||||||
//~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
|
|
||||||
//~| NOTE unexpected token
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,10 @@ help: escape `return` to use it as an identifier
|
||||||
|
|
|
|
||||||
LL | r#return
|
LL | r#return
|
||||||
| ++
|
| ++
|
||||||
|
help: you might have meant to start a match arm after the match guard
|
||||||
error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
|
|
||||||
--> $DIR/issue-15980.rs:13:9
|
|
||||||
|
|
|
|
||||||
LL | }
|
LL | Err(ref e) if e.kind == io::EndOfFile => {
|
||||||
| - expected one of `.`, `=>`, `?`, or an operator
|
| ++
|
||||||
LL |
|
|
||||||
LL | _ => {}
|
|
||||||
| ^ unexpected token
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,15 @@ error: expected one of `,`, `:`, or `}`, found `.`
|
||||||
--> $DIR/issue-52496.rs:8:22
|
--> $DIR/issue-52496.rs:8:22
|
||||||
|
|
|
|
||||||
LL | let _ = Foo { bar.into(), bat: -1, . };
|
LL | let _ = Foo { bar.into(), bat: -1, . };
|
||||||
| --- - ^ expected one of `,`, `:`, or `}`
|
| --- ---^ expected one of `,`, `:`, or `}`
|
||||||
| | |
|
| | |
|
||||||
| | help: try naming a field: `bar:`
|
| | while parsing this struct field
|
||||||
| while parsing this struct
|
| while parsing this struct
|
||||||
|
|
|
||||||
|
help: try naming a field
|
||||||
|
|
|
||||||
|
LL | let _ = Foo { bar: bar.into(), bat: -1, . };
|
||||||
|
| ++++
|
||||||
|
|
||||||
error: expected identifier, found `.`
|
error: expected identifier, found `.`
|
||||||
--> $DIR/issue-52496.rs:8:40
|
--> $DIR/issue-52496.rs:8:40
|
||||||
|
|
|
@ -8,9 +8,9 @@ fn main() {
|
||||||
let _ = match opt {
|
let _ = match opt {
|
||||||
Some(_) => true,
|
Some(_) => true,
|
||||||
//~^ ERROR: expected one of
|
//~^ ERROR: expected one of
|
||||||
//~| HELP: try using a fat arrow here
|
//~| HELP: use a fat arrow to start a match arm
|
||||||
None => false,
|
None => false,
|
||||||
//~^ ERROR: expected one of
|
//~^ ERROR: expected one of
|
||||||
//~| HELP: try using a fat arrow here
|
//~| HELP: use a fat arrow to start a match arm
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ fn main() {
|
||||||
let _ = match opt {
|
let _ = match opt {
|
||||||
Some(_) = true,
|
Some(_) = true,
|
||||||
//~^ ERROR: expected one of
|
//~^ ERROR: expected one of
|
||||||
//~| HELP: try using a fat arrow here
|
//~| HELP: use a fat arrow to start a match arm
|
||||||
None -> false,
|
None -> false,
|
||||||
//~^ ERROR: expected one of
|
//~^ ERROR: expected one of
|
||||||
//~| HELP: try using a fat arrow here
|
//~| HELP: use a fat arrow to start a match arm
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ LL | Some(_) = true,
|
||||||
| ^
|
| ^
|
||||||
| |
|
| |
|
||||||
| expected one of `=>`, `if`, or `|`
|
| expected one of `=>`, `if`, or `|`
|
||||||
| help: try using a fat arrow here: `=>`
|
| help: use a fat arrow to start a match arm: `=>`
|
||||||
|
|
||||||
error: expected one of `=>`, `@`, `if`, or `|`, found `->`
|
error: expected one of `=>`, `@`, `if`, or `|`, found `->`
|
||||||
--> $DIR/issue-89396.rs:12:14
|
--> $DIR/issue-89396.rs:12:14
|
||||||
|
@ -14,7 +14,7 @@ LL | None -> false,
|
||||||
| ^^
|
| ^^
|
||||||
| |
|
| |
|
||||||
| expected one of `=>`, `@`, `if`, or `|`
|
| expected one of `=>`, `@`, `if`, or `|`
|
||||||
| help: try using a fat arrow here: `=>`
|
| help: use a fat arrow to start a match arm: `=>`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
38
tests/ui/parser/missing-fat-arrow.rs
Normal file
38
tests/ui/parser/missing-fat-arrow.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
fn main() {
|
||||||
|
let x = 1;
|
||||||
|
let y = 2;
|
||||||
|
let value = 3;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
Some(x) if x == y {
|
||||||
|
self.next_token()?; //~ ERROR expected identifier, found keyword `self`
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let _: i32 = (); //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
value: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(a: Option<&mut Foo>, b: usize) {
|
||||||
|
match a {
|
||||||
|
Some(a) if a.value == b {
|
||||||
|
a.value = 1; //~ ERROR expected one of `,`, `:`, or `}`, found `.`
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let _: i32 = (); //~ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(a: Option<&mut Foo>, b: usize) {
|
||||||
|
match a {
|
||||||
|
Some(a) if a.value == b {
|
||||||
|
a.value, //~ ERROR expected one of `,`, `:`, or `}`, found `.`
|
||||||
|
} => {
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let _: i32 = (); //~ ERROR mismatched types
|
||||||
|
}
|
78
tests/ui/parser/missing-fat-arrow.stderr
Normal file
78
tests/ui/parser/missing-fat-arrow.stderr
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
error: expected identifier, found keyword `self`
|
||||||
|
--> $DIR/missing-fat-arrow.rs:8:13
|
||||||
|
|
|
||||||
|
LL | Some(x) if x == y {
|
||||||
|
| - while parsing this struct
|
||||||
|
LL | self.next_token()?;
|
||||||
|
| ^^^^ expected identifier, found keyword
|
||||||
|
|
|
||||||
|
help: you might have meant to start a match arm after the match guard
|
||||||
|
|
|
||||||
|
LL | Some(x) if x == y => {
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error: expected one of `,`, `:`, or `}`, found `.`
|
||||||
|
--> $DIR/missing-fat-arrow.rs:22:14
|
||||||
|
|
|
||||||
|
LL | Some(a) if a.value == b {
|
||||||
|
| - while parsing this struct
|
||||||
|
LL | a.value = 1;
|
||||||
|
| -^ expected one of `,`, `:`, or `}`
|
||||||
|
| |
|
||||||
|
| while parsing this struct field
|
||||||
|
|
|
||||||
|
help: try naming a field
|
||||||
|
|
|
||||||
|
LL | a: a.value = 1;
|
||||||
|
| ++
|
||||||
|
help: you might have meant to start a match arm after the match guard
|
||||||
|
|
|
||||||
|
LL | Some(a) if a.value == b => {
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error: expected one of `,`, `:`, or `}`, found `.`
|
||||||
|
--> $DIR/missing-fat-arrow.rs:32:14
|
||||||
|
|
|
||||||
|
LL | Some(a) if a.value == b {
|
||||||
|
| - while parsing this struct
|
||||||
|
LL | a.value,
|
||||||
|
| -^ expected one of `,`, `:`, or `}`
|
||||||
|
| |
|
||||||
|
| while parsing this struct field
|
||||||
|
|
|
||||||
|
help: try naming a field
|
||||||
|
|
|
||||||
|
LL | a: a.value,
|
||||||
|
| ++
|
||||||
|
help: you might have meant to start a match arm after the match guard
|
||||||
|
|
|
||||||
|
LL | Some(a) if a.value == b => {
|
||||||
|
| ++
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/missing-fat-arrow.rs:12:18
|
||||||
|
|
|
||||||
|
LL | let _: i32 = ();
|
||||||
|
| --- ^^ expected `i32`, found `()`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/missing-fat-arrow.rs:26:18
|
||||||
|
|
|
||||||
|
LL | let _: i32 = ();
|
||||||
|
| --- ^^ expected `i32`, found `()`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/missing-fat-arrow.rs:37:18
|
||||||
|
|
|
||||||
|
LL | let _: i32 = ();
|
||||||
|
| --- ^^ expected `i32`, found `()`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -2,8 +2,9 @@ error: expected one of `,`, `:`, or `}`, found `a`
|
||||||
--> $DIR/removed-syntax-with-2.rs:8:31
|
--> $DIR/removed-syntax-with-2.rs:8:31
|
||||||
|
|
|
|
||||||
LL | let b = S { foo: (), with a };
|
LL | let b = S { foo: (), with a };
|
||||||
| - ^ expected one of `,`, `:`, or `}`
|
| - ---- ^ expected one of `,`, `:`, or `}`
|
||||||
| |
|
| | |
|
||||||
|
| | while parsing this struct field
|
||||||
| while parsing this struct
|
| while parsing this struct
|
||||||
|
|
||||||
error[E0063]: missing field `bar` in initializer of `S`
|
error[E0063]: missing field `bar` in initializer of `S`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue