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 6 pull requests #106743

Merged
merged 12 commits into from
Jan 12, 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
18 changes: 9 additions & 9 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// There are a few environmental pre-conditions that shape how the system
// is set up:
//
// - Error reporting only can happen on the main thread because that's the
// - Error reporting can only happen on the main thread because that's the
// only place where we have access to the compiler `Session`.
// - LLVM work can be done on any thread.
// - Codegen can only happen on the main thread.
Expand All @@ -1110,16 +1110,16 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Error Reporting
// ===============
// The error reporting restriction is handled separately from the rest: We
// set up a `SharedEmitter` the holds an open channel to the main thread.
// set up a `SharedEmitter` that holds an open channel to the main thread.
// When an error occurs on any thread, the shared emitter will send the
// error message to the receiver main thread (`SharedEmitterMain`). The
// main thread will periodically query this error message queue and emit
// any error messages it has received. It might even abort compilation if
// has received a fatal error. In this case we rely on all other threads
// it has received a fatal error. In this case we rely on all other threads
// being torn down automatically with the main thread.
// Since the main thread will often be busy doing codegen work, error
// reporting will be somewhat delayed, since the message queue can only be
// checked in between to work packages.
// checked in between two work packages.
//
// Work Processing Infrastructure
// ==============================
Expand All @@ -1133,7 +1133,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// thread about what work to do when, and it will spawn off LLVM worker
// threads as open LLVM WorkItems become available.
//
// The job of the main thread is to codegen CGUs into LLVM work package
// The job of the main thread is to codegen CGUs into LLVM work packages
// (since the main thread is the only thread that can do this). The main
// thread will block until it receives a message from the coordinator, upon
// which it will codegen one CGU, send it to the coordinator and block
Expand All @@ -1142,10 +1142,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
//
// The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is
// available, it will spawn off a new LLVM worker thread and let it process
// that a WorkItem. When a LLVM worker thread is done with its WorkItem,
// a WorkItem. When a LLVM worker thread is done with its WorkItem,
// it will just shut down, which also frees all resources associated with
// the given LLVM module, and sends a message to the coordinator that the
// has been completed.
// WorkItem has been completed.
//
// Work Scheduling
// ===============
Expand All @@ -1165,7 +1165,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
//
// Doing LLVM Work on the Main Thread
// ----------------------------------
// Since the main thread owns the compiler processes implicit `Token`, it is
// Since the main thread owns the compiler process's implicit `Token`, it is
// wasteful to keep it blocked without doing any work. Therefore, what we do
// in this case is: We spawn off an additional LLVM worker thread that helps
// reduce the queue. The work it is doing corresponds to the implicit
Expand Down Expand Up @@ -1216,7 +1216,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// ------------------------------
//
// The final job the coordinator thread is responsible for is managing LTO
// and how that works. When LTO is requested what we'll to is collect all
// and how that works. When LTO is requested what we'll do is collect all
// optimized LLVM modules into a local vector on the coordinator. Once all
// modules have been codegened and optimized we hand this to the `lto`
// module for further optimization. The `lto` module will return back a list
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
.label = lower bound larger than upper bound
.teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.

mir_build_literal_in_range_out_of_bounds =
literal out of range for `{$ty}`
.label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`

mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper

mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/parse.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ parse_struct_literal_body_without_path =
struct literal body without path
.suggestion = you might have forgotten to add the struct literal inside the block

parse_struct_literal_needing_parens =
invalid struct literal
.suggestion = you might need to surround the struct literal in parentheses

parse_maybe_report_ambiguous_plus =
ambiguous `+` in a type
.suggestion = use parentheses to disambiguate
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_mir_build/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,16 @@ pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
pub teach: Option<()>,
}

#[derive(Diagnostic)]
#[diag(mir_build_literal_in_range_out_of_bounds)]
pub struct LiteralOutOfRange<'tcx> {
#[primary_span]
#[label]
pub span: Span,
pub ty: Ty<'tcx>,
pub max: u128,
}

#[derive(Diagnostic)]
#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
pub struct LowerRangeBoundMustBeLessThanUpper {
Expand Down
68 changes: 62 additions & 6 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hi: mir::ConstantKind<'tcx>,
end: RangeEnd,
span: Span,
lo_expr: Option<&hir::Expr<'tcx>>,
hi_expr: Option<&hir::Expr<'tcx>>,
) -> PatKind<'tcx> {
assert_eq!(lo.ty(), ty);
assert_eq!(hi.ty(), ty);
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
let max = || {
self.tcx
.layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty))
.ok()
.unwrap()
.size
.unsigned_int_max()
};
match (end, cmp) {
// `x..y` where `x < y`.
// Non-empty because the range includes at least `x`.
Expand All @@ -141,7 +151,27 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
// `x..y` where `x >= y`. The range is empty => error.
(RangeEnd::Excluded, _) => {
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
let mut lower_overflow = false;
let mut higher_overflow = false;
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
lower_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
}
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
higher_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
}
if !lower_overflow && !higher_overflow {
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
}
PatKind::Wild
}
// `x..=y` where `x == y`.
Expand All @@ -152,10 +182,34 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
// `x..=y` where `x > y` hence the range is empty => error.
(RangeEnd::Included, _) => {
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
span,
teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
});
let mut lower_overflow = false;
let mut higher_overflow = false;
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
lower_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
}
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
higher_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
}
if !lower_overflow && !higher_overflow {
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
span,
teach: if self.tcx.sess.teach(&error_code!(E0030)) {
Some(())
} else {
None
},
});
}
PatKind::Wild
}
}
Expand Down Expand Up @@ -201,7 +255,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {

let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x));
let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) {
Some((lc, hc)) => self.lower_pattern_range(ty, lc, hc, end, lo_span),
Some((lc, hc)) => {
self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
}
None => {
let msg = &format!(
"found bad range pattern `{:?}` outside of error recovery",
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,24 @@ pub(crate) struct StructLiteralBodyWithoutPathSugg {
pub after: Span,
}

#[derive(Diagnostic)]
#[diag(parse_struct_literal_needing_parens)]
pub(crate) struct StructLiteralNeedingParens {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub sugg: StructLiteralNeedingParensSugg,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(suggestion, applicability = "machine-applicable")]
pub(crate) struct StructLiteralNeedingParensSugg {
#[suggestion_part(code = "(")]
pub before: Span,
#[suggestion_part(code = ")")]
pub after: Span,
}

#[derive(Diagnostic)]
#[diag(parse_unmatched_angle_brackets)]
pub(crate) struct UnmatchedAngleBrackets {
Expand Down
37 changes: 26 additions & 11 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ use crate::errors::{
IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead,
ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType,
QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath,
StructLiteralBodyWithoutPathSugg, SuggEscapeToUseAsIdentifier, SuggRemoveComma,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg,
SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam,
UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets,
UseEqInstead,
};

use crate::lexer::UnmatchedBrace;
Expand Down Expand Up @@ -623,12 +624,15 @@ impl<'a> Parser<'a> {
&mut self,
lo: Span,
s: BlockCheckMode,
maybe_struct_name: token::Token,
can_be_struct_literal: bool,
) -> Option<PResult<'a, P<Block>>> {
if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
// We might be having a struct literal where people forgot to include the path:
// fn foo() -> Foo {
// field: value,
// }
info!(?maybe_struct_name, ?self.token);
let mut snapshot = self.create_snapshot_for_diagnostic();
let path = Path {
segments: ThinVec::new(),
Expand All @@ -648,21 +652,32 @@ impl<'a> Parser<'a> {
// field: value,
// } }
err.delay_as_bug();
self.sess.emit_err(StructLiteralBodyWithoutPath {
span: expr.span,
sugg: StructLiteralBodyWithoutPathSugg {
before: expr.span.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
});
self.restore_snapshot(snapshot);
let mut tail = self.mk_block(
vec![self.mk_stmt_err(expr.span)],
s,
lo.to(self.prev_token.span),
);
tail.could_be_bare_literal = true;
Ok(tail)
if maybe_struct_name.is_ident() && can_be_struct_literal {
// Account for `if Example { a: one(), }.is_pos() {}`.
Err(self.sess.create_err(StructLiteralNeedingParens {
span: maybe_struct_name.span.to(expr.span),
sugg: StructLiteralNeedingParensSugg {
before: maybe_struct_name.span.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
}))
} else {
self.sess.emit_err(StructLiteralBodyWithoutPath {
span: expr.span,
sugg: StructLiteralBodyWithoutPathSugg {
before: expr.span.shrink_to_lo(),
after: expr.span.shrink_to_hi(),
},
});
Ok(tail)
}
}
(Err(err), Ok(tail)) => {
// We have a block tail that contains a somehow valid type ascription expr.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2039,7 +2039,7 @@ impl<'a> Parser<'a> {
});
}

let (attrs, blk) = self.parse_block_common(lo, blk_mode)?;
let (attrs, blk) = self.parse_block_common(lo, blk_mode, true)?;
Ok(self.mk_expr_with_attrs(blk.span, ExprKind::Block(blk, opt_label), attrs))
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2214,7 +2214,8 @@ impl<'a> Parser<'a> {
*sig_hi = self.prev_token.span;
(AttrVec::new(), None)
} else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
self.parse_block_common(self.token.span, BlockCheckMode::Default, false)
.map(|(attrs, body)| (attrs, Some(body)))?
} else if self.token.kind == token::Eq {
// Recover `fn foo() = $expr;`.
self.bump(); // `=`
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_parse/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,24 +498,31 @@ impl<'a> Parser<'a> {

/// Parses a block. Inner attributes are allowed.
pub(super) fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (AttrVec, P<Block>)> {
self.parse_block_common(self.token.span, BlockCheckMode::Default)
self.parse_block_common(self.token.span, BlockCheckMode::Default, true)
}

/// Parses a block. Inner attributes are allowed.
pub(super) fn parse_block_common(
&mut self,
lo: Span,
blk_mode: BlockCheckMode,
can_be_struct_literal: bool,
) -> PResult<'a, (AttrVec, P<Block>)> {
maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x));

let maybe_ident = self.prev_token.clone();
self.maybe_recover_unexpected_block_label();
if !self.eat(&token::OpenDelim(Delimiter::Brace)) {
return self.error_block_no_opening_brace();
}

let attrs = self.parse_inner_attributes()?;
let tail = match self.maybe_suggest_struct_literal(lo, blk_mode) {
let tail = match self.maybe_suggest_struct_literal(
lo,
blk_mode,
maybe_ident,
can_be_struct_literal,
) {
Some(tail) => tail?,
None => self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?,
};
Expand Down
Loading