Rollup merge of #146581 - estebank:issue-146489, r=lcnr
Detect attempt to use var-args in closure
```
error: unexpected `...`
--> $DIR/no-closure.rs:11:14
|
LL | let f = |...| {};
| ^^^ not a valid pattern
|
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: unexpected `...`
--> $DIR/no-closure.rs:16:17
|
LL | let f = |_: ...| {};
| ^^^
|
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
```
Fix rust-lang/rust#146489, when trying to use c-style var-args in a closure. We emit a more targeted message. We also silence inference errors when the pattern is `PatKind::Err`.
This commit is contained in:
commit
61f53585aa
7 changed files with 71 additions and 36 deletions
|
|
@ -189,6 +189,10 @@ parse_dotdotdot = unexpected token: `...`
|
|||
parse_dotdotdot_rest_pattern = unexpected `...`
|
||||
.label = not a valid pattern
|
||||
.suggestion = for a rest pattern, use `..` instead of `...`
|
||||
.note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
parse_dotdotdot_rest_type = unexpected `...`
|
||||
.note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
parse_double_colon_in_bound = expected `:` followed by trait or lifetime
|
||||
.suggestion = use single colon
|
||||
|
|
|
|||
|
|
@ -2723,7 +2723,9 @@ pub(crate) struct DotDotDotRestPattern {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
#[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
pub suggestion: Option<Span>,
|
||||
#[note]
|
||||
pub var_args: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -3030,6 +3032,14 @@ pub(crate) struct NestedCVariadicType {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_dotdotdot_rest_type)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidCVariadicType {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_invalid_dyn_keyword)]
|
||||
#[help]
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump(); // `..`
|
||||
PatKind::Rest
|
||||
} else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) {
|
||||
self.recover_dotdotdot_rest_pat(lo)
|
||||
self.recover_dotdotdot_rest_pat(lo, expected)
|
||||
} else if let Some(form) = self.parse_range_end() {
|
||||
self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
|
||||
} else if self.eat(exp!(Bang)) {
|
||||
|
|
@ -886,16 +886,27 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Recover from a typoed `...` pattern that was encountered
|
||||
/// Ref: Issue #70388
|
||||
fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
|
||||
fn recover_dotdotdot_rest_pat(&mut self, lo: Span, expected: Option<Expected>) -> PatKind {
|
||||
// A typoed rest pattern `...`.
|
||||
self.bump(); // `...`
|
||||
|
||||
// The user probably mistook `...` for a rest pattern `..`.
|
||||
self.dcx().emit_err(DotDotDotRestPattern {
|
||||
span: lo,
|
||||
suggestion: lo.with_lo(lo.hi() - BytePos(1)),
|
||||
});
|
||||
PatKind::Rest
|
||||
if let Some(Expected::ParameterName) = expected {
|
||||
// We have `...` in a closure argument, likely meant to be var-arg, which aren't
|
||||
// supported in closures (#146489).
|
||||
PatKind::Err(self.dcx().emit_err(DotDotDotRestPattern {
|
||||
span: lo,
|
||||
suggestion: None,
|
||||
var_args: Some(()),
|
||||
}))
|
||||
} else {
|
||||
// The user probably mistook `...` for a rest pattern `..`.
|
||||
self.dcx().emit_err(DotDotDotRestPattern {
|
||||
span: lo,
|
||||
suggestion: Some(lo.with_lo(lo.hi() - BytePos(1))),
|
||||
var_args: None,
|
||||
});
|
||||
PatKind::Rest
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
|
|||
use crate::errors::{
|
||||
self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword,
|
||||
ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg,
|
||||
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NestedCVariadicType, ReturnTypesUseThinArrow,
|
||||
HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut,
|
||||
NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow,
|
||||
};
|
||||
use crate::parser::item::FrontMatterParsingMode;
|
||||
use crate::parser::{FnContext, FnParseMode};
|
||||
|
|
@ -106,6 +106,15 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
|
|||
impl<'a> Parser<'a> {
|
||||
/// Parses a type.
|
||||
pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> {
|
||||
if self.token == token::DotDotDot {
|
||||
// We special case this so that we don't talk about "nested C-variadics" in types.
|
||||
// We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about
|
||||
// things like `Vec<...>`.
|
||||
let span = self.token.span;
|
||||
self.bump();
|
||||
let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span }));
|
||||
return Ok(self.mk_ty(span, kind));
|
||||
}
|
||||
// Make sure deeply nested types don't overflow the stack.
|
||||
ensure_sufficient_stack(|| {
|
||||
self.parse_ty_common(
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ use std::path::PathBuf;
|
|||
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Diag, IntoDiagArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
|
||||
use rustc_hir::{
|
||||
self as hir, Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource, PatKind,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
|
|
@ -512,7 +513,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
type_name: ty_to_string(self, ty, def_id),
|
||||
});
|
||||
}
|
||||
InferSourceKind::ClosureArg { insert_span, ty } => {
|
||||
InferSourceKind::ClosureArg { insert_span, ty, .. } => {
|
||||
infer_subdiags.push(SourceKindSubdiag::LetLike {
|
||||
span: insert_span,
|
||||
name: String::new(),
|
||||
|
|
@ -652,6 +653,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
}),
|
||||
};
|
||||
*err.long_ty_path() = long_ty_path;
|
||||
if let InferSourceKind::ClosureArg { kind: PatKind::Err(_), .. } = kind {
|
||||
// We will have already emitted an error about this pattern.
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
err
|
||||
}
|
||||
}
|
||||
|
|
@ -673,6 +678,7 @@ enum InferSourceKind<'tcx> {
|
|||
ClosureArg {
|
||||
insert_span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
kind: PatKind<'tcx>,
|
||||
},
|
||||
GenericArg {
|
||||
insert_span: Span,
|
||||
|
|
@ -1197,6 +1203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
|
|||
kind: InferSourceKind::ClosureArg {
|
||||
insert_span: param.pat.span.shrink_to_hi(),
|
||||
ty: param_ty,
|
||||
kind: param.pat.kind,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,17 @@
|
|||
// Check that `...` in closures is rejected.
|
||||
|
||||
const F: extern "C" fn(...) = |_: ...| {};
|
||||
//~^ ERROR C-variadic type `...` may not be nested inside another type
|
||||
//~^ ERROR: unexpected `...`
|
||||
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
fn foo() {
|
||||
let f = |...| {};
|
||||
//~^ ERROR: `..` patterns are not allowed here
|
||||
//~| ERROR: unexpected `...`
|
||||
//~^ ERROR: unexpected `...`
|
||||
//~| NOTE: not a valid pattern
|
||||
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
let f = |_: ...| {};
|
||||
//~^ ERROR C-variadic type `...` may not be nested inside another type
|
||||
//~^ ERROR: unexpected `...`
|
||||
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
f(1i64)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,26 @@
|
|||
error[E0743]: C-variadic type `...` may not be nested inside another type
|
||||
error: unexpected `...`
|
||||
--> $DIR/no-closure.rs:6:35
|
||||
|
|
||||
LL | const F: extern "C" fn(...) = |_: ...| {};
|
||||
| ^^^
|
||||
|
|
||||
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
error: unexpected `...`
|
||||
--> $DIR/no-closure.rs:10:14
|
||||
--> $DIR/no-closure.rs:11:14
|
||||
|
|
||||
LL | let f = |...| {};
|
||||
| ^^^ not a valid pattern
|
||||
|
|
||||
help: for a rest pattern, use `..` instead of `...`
|
||||
|
|
||||
LL - let f = |...| {};
|
||||
LL + let f = |..| {};
|
||||
|
|
||||
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
error[E0743]: C-variadic type `...` may not be nested inside another type
|
||||
--> $DIR/no-closure.rs:14:17
|
||||
error: unexpected `...`
|
||||
--> $DIR/no-closure.rs:16:17
|
||||
|
|
||||
LL | let f = |_: ...| {};
|
||||
| ^^^
|
||||
|
||||
error: `..` patterns are not allowed here
|
||||
--> $DIR/no-closure.rs:10:14
|
||||
|
|
||||
LL | let f = |...| {};
|
||||
| ^^^
|
||||
|
|
||||
= note: only allowed in tuple, tuple struct, and slice patterns
|
||||
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0743`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue