Skip to content
Open
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
10 changes: 6 additions & 4 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,13 @@ impl<'a> AstValidator<'a> {
self.disallow_tilde_const = old;
}

fn check_type_alias_where_clause_location(
fn check_type_alias_where_clause_not_leading(
&mut self,
ty_alias: &TyAlias,
) -> Result<(), diagnostics::WhereClauseBeforeTypeAlias> {
if ty_alias.ty.is_none() || !ty_alias.generics.where_clause.has_where_token {
if !ty_alias.generics.where_clause.has_where_token
|| ty_alias.ty.is_none() && !ty_alias.after_where_clause.has_where_token
{
return Ok(());
}

Expand Down Expand Up @@ -1722,7 +1724,7 @@ impl Visitor<'_> for AstValidator<'_> {
self.check_type_no_bounds(bounds, "this context");

if self.features.checked_type_aliases() {
if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
if let Err(err) = self.check_type_alias_where_clause_not_leading(ty_alias) {
self.dcx().emit_err(err);
}
} else if after_where_clause.has_where_token {
Expand Down Expand Up @@ -2106,7 +2108,7 @@ impl Visitor<'_> for AstValidator<'_> {
}

if let AssocItemKind::Type(ty_alias) = &item.kind
&& let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
&& let Err(err) = self.check_type_alias_where_clause_not_leading(ty_alias)
{
let sugg = match err.sugg {
diagnostics::WhereClauseBeforeTypeAliasSugg::Remove { .. } => None,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_parse/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2624,7 +2624,7 @@ pub(crate) struct MultipleWhereClauses {
code = ",",
applicability = "maybe-incorrect"
)]
pub between: Span,
pub between: Option<Span>,
}

#[derive(Diagnostic)]
Expand Down Expand Up @@ -4088,7 +4088,7 @@ pub(crate) struct StaticWithGenerics {

#[derive(Diagnostic)]
#[diag("where clauses are not allowed before const item bodies")]
pub(crate) struct WhereClauseBeforeConstBody {
pub(crate) struct WhereClauseBeforeConstItemBody {
#[primary_span]
#[label("unexpected where clause")]
pub span: Span,
Expand Down
19 changes: 15 additions & 4 deletions compiler/rustc_parse/src/parser/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use thin_vec::ThinVec;
use tracing::debug;

use super::diagnostics::dummy_arg;
use super::generics::RecoverDupeWhereClause;
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
ExpKeywordPair, FollowedByType, ForceCollect, Parser, Recovered, Trailing, UsePreAttrPos,
Expand Down Expand Up @@ -123,8 +124,9 @@ impl<'a> Parser<'a> {
fn_parse_mode: FnParseMode,
sig_lo: Span,
vis: &Visibility,
defaultness: Defaultness,
case: Case,
) -> PResult<'a, (Ident, FnSig, Generics, Option<Box<FnContract>>, Option<Box<Block>>)> {
) -> PResult<'a, ItemKind> {
let fn_span = self.token.span;
let header = self.parse_fn_front_matter(vis, case, FrontMatterParsingMode::Function)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
Expand All @@ -151,7 +153,7 @@ impl<'a> Parser<'a> {

let contract = self.parse_contract()?;

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

// `fn_params_end` is needed only when it's followed by a where clause.
let fn_params_end =
Expand All @@ -161,8 +163,17 @@ impl<'a> Parser<'a> {
// 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, contract, body))

Ok(ItemKind::Fn(Box::new(Fn {
defaultness,
ident,
sig: FnSig { header, decl, span: sig_lo.to(sig_hi) },
generics,
contract,
body,
define_opaque: None,
eii_impl: None,
})))
}

/// Provide diagnostics when function body is not found
Expand Down
43 changes: 30 additions & 13 deletions compiler/rustc_parse/src/parser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ use crate::diagnostics::{
};
use crate::exp;

pub(super) enum RecoverDupeWhereClause {
Yes,
No,
}

enum PredicateKindOrStructBody {
PredicateKind(ast::WherePredicateKind),
StructBody(ThinVec<ast::FieldDef>),
Expand Down Expand Up @@ -395,21 +400,28 @@ impl<'a> Parser<'a> {
/// ```ignore (only-for-syntax-highlight)
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
self.parse_where_clause_common(None).map(|(clause, _)| clause)
pub(super) fn parse_where_clause(
&mut self,
recover_dupe: RecoverDupeWhereClause,
) -> PResult<'a, WhereClause> {
self.parse_where_clause_common(None, recover_dupe).map(|(clause, _)| clause)
}

pub(super) fn parse_struct_where_clause(
&mut self,
struct_name: Ident,
body_insertion_point: Span,
) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
self.parse_where_clause_common(Some((struct_name, body_insertion_point)))
self.parse_where_clause_common(
Some((struct_name, body_insertion_point)),
RecoverDupeWhereClause::Yes,
)
}

fn parse_where_clause_common(
&mut self,
struct_: Option<(Ident, Span)>,
recover_dupe: RecoverDupeWhereClause,
) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
if !self.eat_keyword(exp!(Where)) {
return Ok((
Expand Down Expand Up @@ -446,7 +458,7 @@ impl<'a> Parser<'a> {
}

let (predicates, tuple_struct_body) =
self.parse_where_clause_predicates(struct_, where_lo)?;
self.parse_where_clause_predicates(struct_, where_lo, recover_dupe)?;
let where_clause = WhereClause {
has_where_token: true,
predicates,
Expand All @@ -459,6 +471,7 @@ impl<'a> Parser<'a> {
&mut self,
struct_: Option<(Ident, Span)>,
where_lo: Span,
recover_dupe: RecoverDupeWhereClause,
) -> PResult<'a, (ThinVec<WherePredicate>, Option<ThinVec<ast::FieldDef>>)> {
let mut predicates = ThinVec::new();
let mut tuple_struct_body = None;
Expand Down Expand Up @@ -514,19 +527,23 @@ impl<'a> Parser<'a> {
});
Ok((predicate, Trailing::No, UsePreAttrPos::No))
})?;
match predicate {
Some(predicate) => predicates.push(predicate),
None => break,

let has_parsed_pred = predicate.is_some();
if let Some(pred) = predicate {
predicates.push(pred);
}

let prev_token = self.prev_token.span;
let ate_comma = self.eat(exp!(Comma));
let pred_hi = self.prev_token.span;
let ate_comma = has_parsed_pred && self.eat(exp!(Comma));

if self.eat_keyword_noexpect(kw::Where) {
if let RecoverDupeWhereClause::Yes = recover_dupe
&& self.eat_keyword_noexpect(kw::Where)
{
self.dcx().emit_err(MultipleWhereClauses {
span: self.token.span,
previous: pred_lo,
between: prev_token.shrink_to_hi().to(self.prev_token.span),
span: self.prev_token.span,
previous: where_sp,
between: has_parsed_pred
.then(|| pred_hi.shrink_to_hi().to(self.prev_token.span)),
});
} else if !ate_comma {
break;
Expand Down
Loading
Loading