Skip to content

Commit

Permalink
Auto merge of #106743 - matthiaskrgr:rollup-q5dpxms, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #106620 (Detect struct literal needing parentheses)
 - #106622 (Detect out of bounds range pattern value)
 - #106703 (Note predicate span on `ImplDerivedObligation`)
 - #106705 (Report fulfillment errors in new trait solver)
 - #106726 (Fix some typos in code comments.)
 - #106734 (Deny having src/test exisiting in tidy)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 11, 2023
2 parents 1e4f900 + 106df9e commit 56ee65a
Show file tree
Hide file tree
Showing 70 changed files with 452 additions and 109 deletions.
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

0 comments on commit 56ee65a

Please sign in to comment.