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 #127957

Merged
merged 18 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5834772
Update Tests
veera-sivarajan Jul 4, 2024
cf09cba
When finding item gated behind a `cfg` flat, point at it
estebank Jul 12, 2024
9dc08e3
Rewrite and rename issue-22131 to rmake
Oneirical Jul 11, 2024
fc4404c
Rewrite and rename issue-26006 to rmake
Oneirical Jul 11, 2024
2e1e627
rustdoc: fix `current` class on sidebar modnav
notriddle Jul 18, 2024
4cad705
Parser: Suggest Placing the Return Type After Function Parameters
veera-sivarajan Jul 4, 2024
2f5a84e
Don't allow unsafe statics outside of extern blocks
compiler-errors Jul 18, 2024
e69ff1c
Remove an unnecessary `ForceCollect::Yes`.
nnethercote Jul 16, 2024
7d7e2a1
Don't always force collect tokens in `recover_stmt_local_after_let`.
nnethercote Jul 16, 2024
9d908a2
Use `ForceCollect` in `parse_attr_item`.
nnethercote Jul 17, 2024
4158a1c
Only check `force_collect` in `collect_tokens_trailing_token`.
nnethercote Jul 17, 2024
0c932b7
Rearrange sidebar modnav builder to more logical order
notriddle Jul 19, 2024
c86e13f
Rollup merge of #127350 - veera-sivarajan:bugfix-126311, r=lcnr
matthiaskrgr Jul 19, 2024
7161e2d
Rollup merge of #127621 - Oneirical:hypnotest-show, r=jieyouxu
matthiaskrgr Jul 19, 2024
98fdfcb
Rollup merge of #127662 - estebank:gate-span, r=TaKO8Ki
matthiaskrgr Jul 19, 2024
9ada89d
Rollup merge of #127903 - nnethercote:force_collect-improvements, r=p…
matthiaskrgr Jul 19, 2024
1c66573
Rollup merge of #127932 - notriddle:notriddle/current, r=GuillaumeGomez
matthiaskrgr Jul 19, 2024
6fe68f8
Rollup merge of #127943 - compiler-errors:no-unsafe, r=spastorino
matthiaskrgr Jul 19, 2024
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
3 changes: 3 additions & 0 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
.negative = negative because of this
.unsafe = unsafe because of this

ast_passes_unsafe_static =
static items cannot be declared with `unsafe` safety qualifier outside of `extern` block

ast_passes_visibility_not_permitted =
visibility qualifiers are not permitted here
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,11 @@ impl<'a> AstValidator<'a> {
}
}

/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
/// blocks.
///
/// This additionally ensures that within extern blocks, items can only be
/// `safe`/`unsafe` inside of a `unsafe`-adorned extern block.
fn check_item_safety(&self, span: Span, safety: Safety) {
match self.extern_mod_safety {
Some(extern_safety) => {
Expand Down Expand Up @@ -1177,6 +1182,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
self.check_item_safety(item.span, *safety);
if matches!(safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::UnsafeStatic { span: item.span });
}

if expr.is_none() {
self.dcx().emit_err(errors::StaticWithoutBody {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ pub struct InvalidSafetyOnBareFn {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_unsafe_static)]
pub struct UnsafeStatic {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_bound_in_context)]
pub struct BoundInContext<'a> {
Expand Down
16 changes: 9 additions & 7 deletions compiler/rustc_builtin_macros/src/cmdline_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::errors;
use rustc_ast::attr::mk_attr;
use rustc_ast::token;
use rustc_ast::{self as ast, AttrItem, AttrStyle};
use rustc_parse::parser::ForceCollect;
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_session::parse::ParseSess;
use rustc_span::FileName;
Expand All @@ -17,13 +18,14 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
));

let start_span = parser.token.span;
let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
Ok(ai) => ai,
Err(err) => {
err.emit();
continue;
}
};
let AttrItem { unsafety, path, args, tokens: _ } =
match parser.parse_attr_item(ForceCollect::No) {
Ok(ai) => ai,
Err(err) => {
err.emit();
continue;
}
};
let end_span = parser.token.span;
if parser.token != token::Eof {
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@ parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}
.label_opening_candidate = closing delimiter possibly meant for this
.label_unclosed = unclosed delimiter

parse_misplaced_return_type = place the return type after the function parameters

parse_missing_comma_after_match_arm = expected `,` following `match` arm
.suggestion = missing a comma here to end this `match` arm

Expand Down
22 changes: 15 additions & 7 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1502,6 +1502,20 @@ pub(crate) struct FnPtrWithGenerics {
pub sugg: Option<FnPtrWithGenericsSugg>,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
parse_misplaced_return_type,
style = "verbose",
applicability = "maybe-incorrect"
)]
pub(crate) struct MisplacedReturnType {
#[suggestion_part(code = " {snippet}")]
pub fn_params_end: Span,
pub snippet: String,
#[suggestion_part(code = "")]
pub ret_ty_span: Span,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")]
pub(crate) struct FnPtrWithGenericsSugg {
Expand All @@ -1516,7 +1530,6 @@ pub(crate) struct FnPtrWithGenericsSugg {

pub(crate) struct FnTraitMissingParen {
pub span: Span,
pub machine_applicable: bool,
}

impl Subdiagnostic for FnTraitMissingParen {
Expand All @@ -1526,16 +1539,11 @@ impl Subdiagnostic for FnTraitMissingParen {
_: &F,
) {
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
let applicability = if self.machine_applicable {
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
diag.span_suggestion_short(
self.span.shrink_to_hi(),
crate::fluent_generated::parse_add_paren,
"()",
applicability,
Applicability::MachineApplicable,
);
}
}
Expand Down
15 changes: 7 additions & 8 deletions compiler/rustc_parse/src/parser/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl<'a> Parser<'a> {
if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };

this.expect(&token::OpenDelim(Delimiter::Bracket))?;
let item = this.parse_attr_item(false)?;
let item = this.parse_attr_item(ForceCollect::No)?;
this.expect(&token::CloseDelim(Delimiter::Bracket))?;
let attr_sp = lo.to(this.prev_token.span);

Expand Down Expand Up @@ -248,16 +248,15 @@ impl<'a> Parser<'a> {
/// PATH
/// PATH `=` UNSUFFIXED_LIT
/// The delimiters or `=` are still put into the resulting token stream.
pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> {
maybe_whole!(self, NtMeta, |attr| attr.into_inner());

let do_parse = |this: &mut Self| {
let do_parse = |this: &mut Self, _empty_attrs| {
let is_unsafe = this.eat_keyword(kw::Unsafe);
let unsafety = if is_unsafe {
let unsafe_span = this.prev_token.span;
this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;

ast::Safety::Unsafe(unsafe_span)
} else {
ast::Safety::Default
Expand All @@ -268,10 +267,10 @@ impl<'a> Parser<'a> {
if is_unsafe {
this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
}
Ok(ast::AttrItem { unsafety, path, args, tokens: None })
Ok((ast::AttrItem { unsafety, path, args, tokens: None }, false))
};
// Attr items don't have attributes
if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
// Attr items don't have attributes.
self.collect_tokens_trailing_token(AttrWrapper::empty(), force_collect, do_parse)
}

/// Parses attributes that appear after the opening of an item. These should
Expand Down Expand Up @@ -344,7 +343,7 @@ impl<'a> Parser<'a> {
let mut expanded_attrs = Vec::with_capacity(1);
while self.token.kind != token::Eof {
let lo = self.token.span;
let item = self.parse_attr_item(true)?;
let item = self.parse_attr_item(ForceCollect::Yes)?;
expanded_attrs.push((item, lo.to(self.prev_token.span)));
if !self.eat(&token::Comma) {
break;
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ impl<'a> Parser<'a> {
&mut self,
edible: &[TokenKind],
inedible: &[TokenKind],
) -> PResult<'a, Recovered> {
) -> PResult<'a, ErrorGuaranteed> {
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
fn tokens_to_string(tokens: &[TokenType]) -> String {
let mut i = tokens.iter();
Expand Down Expand Up @@ -533,7 +533,7 @@ impl<'a> Parser<'a> {
sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
});
self.bump();
return Ok(Recovered::Yes(guar));
return Ok(guar);
} else if self.look_ahead(0, |t| {
t == &token::CloseDelim(Delimiter::Brace)
|| ((t.can_begin_expr() || t.can_begin_item())
Expand All @@ -557,7 +557,7 @@ impl<'a> Parser<'a> {
unexpected_token_label: Some(self.token.span),
sugg: ExpectedSemiSugg::AddSemi(span),
});
return Ok(Recovered::Yes(guar));
return Ok(guar);
}
}

Expand Down Expand Up @@ -712,7 +712,7 @@ impl<'a> Parser<'a> {
if self.check_too_many_raw_str_terminators(&mut err) {
if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
let guar = err.emit();
return Ok(Recovered::Yes(guar));
return Ok(guar);
} else {
return Err(err);
}
Expand Down
124 changes: 96 additions & 28 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use rustc_span::edit_distance::edit_distance;
use rustc_span::edition::Edition;
use rustc_span::source_map;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::ErrorGuaranteed;
use rustc_span::{Span, DUMMY_SP};
use std::fmt::Write;
use std::mem;
Expand Down Expand Up @@ -2332,14 +2333,106 @@ impl<'a> Parser<'a> {
}
}
};

// Store the end of function parameters to give better diagnostics
// inside `parse_fn_body()`.
let fn_params_end = self.prev_token.span.shrink_to_hi();

generics.where_clause = self.parse_where_clause()?; // `where T: Ord`

// `fn_params_end` is needed only when it's followed by a where clause.
let fn_params_end =
if generics.where_clause.has_where_token { Some(fn_params_end) } else { None };

let mut sig_hi = self.prev_token.span;
let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`.
// Either `;` or `{ ... }`.
let body =
self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?;
let fn_sig_span = sig_lo.to(sig_hi);
Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body))
}

/// Provide diagnostics when function body is not found
fn error_fn_body_not_found(
&mut self,
ident_span: Span,
req_body: bool,
fn_params_end: Option<Span>,
) -> PResult<'a, ErrorGuaranteed> {
let expected = if req_body {
&[token::OpenDelim(Delimiter::Brace)][..]
} else {
&[token::Semi, token::OpenDelim(Delimiter::Brace)]
};
match self.expected_one_of_not_found(&[], expected) {
Ok(error_guaranteed) => Ok(error_guaranteed),
Err(mut err) => {
if self.token.kind == token::CloseDelim(Delimiter::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
err.span_label(ident_span, "while parsing this `fn`");
Ok(err.emit())
} else if self.token.kind == token::RArrow
&& let Some(fn_params_end) = fn_params_end
{
// Instead of a function body, the parser has encountered a right arrow
// preceded by a where clause.

// Find whether token behind the right arrow is a function trait and
// store its span.
let fn_trait_span =
[sym::FnOnce, sym::FnMut, sym::Fn].into_iter().find_map(|symbol| {
if self.prev_token.is_ident_named(symbol) {
Some(self.prev_token.span)
} else {
None
}
});

// Parse the return type (along with the right arrow) and store its span.
// If there's a parse error, cancel it and return the existing error
// as we are primarily concerned with the
// expected-function-body-but-found-something-else error here.
let arrow_span = self.token.span;
let ty_span = match self.parse_ret_ty(
AllowPlus::Yes,
RecoverQPath::Yes,
RecoverReturnSign::Yes,
) {
Ok(ty_span) => ty_span.span().shrink_to_hi(),
Err(parse_error) => {
parse_error.cancel();
return Err(err);
}
};
let ret_ty_span = arrow_span.to(ty_span);

if let Some(fn_trait_span) = fn_trait_span {
// Typo'd Fn* trait bounds such as
// fn foo<F>() where F: FnOnce -> () {}
err.subdiagnostic(errors::FnTraitMissingParen { span: fn_trait_span });
} else if let Ok(snippet) = self.psess.source_map().span_to_snippet(ret_ty_span)
{
// If token behind right arrow is not a Fn* trait, the programmer
// probably misplaced the return type after the where clause like
// `fn foo<T>() where T: Default -> u8 {}`
err.primary_message(
"return type should be specified after the function parameters",
);
err.subdiagnostic(errors::MisplacedReturnType {
fn_params_end,
snippet,
ret_ty_span,
});
}
Err(err)
} else {
Err(err)
}
}
}
}

/// Parse the "body" of a function.
/// This can either be `;` when there's no body,
/// or e.g. a block when the function is a provided one.
Expand All @@ -2349,6 +2442,7 @@ impl<'a> Parser<'a> {
ident: &Ident,
sig_hi: &mut Span,
req_body: bool,
fn_params_end: Option<Span>,
) -> PResult<'a, Option<P<Block>>> {
let has_semi = if req_body {
self.token.kind == TokenKind::Semi
Expand Down Expand Up @@ -2377,33 +2471,7 @@ impl<'a> Parser<'a> {
});
(AttrVec::new(), Some(self.mk_block_err(span, guar)))
} else {
let expected = if req_body {
&[token::OpenDelim(Delimiter::Brace)][..]
} else {
&[token::Semi, token::OpenDelim(Delimiter::Brace)]
};
if let Err(mut err) = self.expected_one_of_not_found(&[], expected) {
if self.token.kind == token::CloseDelim(Delimiter::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
err.span_label(ident.span, "while parsing this `fn`");
err.emit();
} else {
// check for typo'd Fn* trait bounds such as
// fn foo<F>() where F: FnOnce -> () {}
if self.token.kind == token::RArrow {
let machine_applicable = [sym::FnOnce, sym::FnMut, sym::Fn]
.into_iter()
.any(|s| self.prev_token.is_ident_named(s));

err.subdiagnostic(errors::FnTraitMissingParen {
span: self.prev_token.span,
machine_applicable,
});
}
return Err(err);
}
}
self.error_fn_body_not_found(ident.span, req_body, fn_params_end)?;
(AttrVec::new(), None)
};
attrs.extend(inner_attrs);
Expand Down
Loading
Loading