Skip to content

Commit 5177665

Browse files
authored
Rollup merge of rust-lang#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#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`.
2 parents 667da4e + e9270e3 commit 5177665

File tree

7 files changed

+71
-36
lines changed

7 files changed

+71
-36
lines changed

compiler/rustc_parse/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ parse_dotdotdot = unexpected token: `...`
189189
parse_dotdotdot_rest_pattern = unexpected `...`
190190
.label = not a valid pattern
191191
.suggestion = for a rest pattern, use `..` instead of `...`
192+
.note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
193+
194+
parse_dotdotdot_rest_type = unexpected `...`
195+
.note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
192196
193197
parse_double_colon_in_bound = expected `:` followed by trait or lifetime
194198
.suggestion = use single colon

compiler/rustc_parse/src/errors.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2723,7 +2723,9 @@ pub(crate) struct DotDotDotRestPattern {
27232723
#[label]
27242724
pub span: Span,
27252725
#[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
2726-
pub suggestion: Span,
2726+
pub suggestion: Option<Span>,
2727+
#[note]
2728+
pub var_args: Option<()>,
27272729
}
27282730

27292731
#[derive(Diagnostic)]
@@ -3030,6 +3032,14 @@ pub(crate) struct NestedCVariadicType {
30303032
pub span: Span,
30313033
}
30323034

3035+
#[derive(Diagnostic)]
3036+
#[diag(parse_dotdotdot_rest_type)]
3037+
#[note]
3038+
pub(crate) struct InvalidCVariadicType {
3039+
#[primary_span]
3040+
pub span: Span,
3041+
}
3042+
30333043
#[derive(Diagnostic)]
30343044
#[diag(parse_invalid_dyn_keyword)]
30353045
#[help]

compiler/rustc_parse/src/parser/pat.rs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ impl<'a> Parser<'a> {
756756
self.bump(); // `..`
757757
PatKind::Rest
758758
} else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) {
759-
self.recover_dotdotdot_rest_pat(lo)
759+
self.recover_dotdotdot_rest_pat(lo, expected)
760760
} else if let Some(form) = self.parse_range_end() {
761761
self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`.
762762
} else if self.eat(exp!(Bang)) {
@@ -886,16 +886,27 @@ impl<'a> Parser<'a> {
886886

887887
/// Recover from a typoed `...` pattern that was encountered
888888
/// Ref: Issue #70388
889-
fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
889+
fn recover_dotdotdot_rest_pat(&mut self, lo: Span, expected: Option<Expected>) -> PatKind {
890890
// A typoed rest pattern `...`.
891891
self.bump(); // `...`
892892

893-
// The user probably mistook `...` for a rest pattern `..`.
894-
self.dcx().emit_err(DotDotDotRestPattern {
895-
span: lo,
896-
suggestion: lo.with_lo(lo.hi() - BytePos(1)),
897-
});
898-
PatKind::Rest
893+
if let Some(Expected::ParameterName) = expected {
894+
// We have `...` in a closure argument, likely meant to be var-arg, which aren't
895+
// supported in closures (#146489).
896+
PatKind::Err(self.dcx().emit_err(DotDotDotRestPattern {
897+
span: lo,
898+
suggestion: None,
899+
var_args: Some(()),
900+
}))
901+
} else {
902+
// The user probably mistook `...` for a rest pattern `..`.
903+
self.dcx().emit_err(DotDotDotRestPattern {
904+
span: lo,
905+
suggestion: Some(lo.with_lo(lo.hi() - BytePos(1))),
906+
var_args: None,
907+
});
908+
PatKind::Rest
909+
}
899910
}
900911

901912
/// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`.

compiler/rustc_parse/src/parser/ty.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use super::{Parser, PathStyle, SeqSep, TokenType, Trailing};
1515
use crate::errors::{
1616
self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword,
1717
ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg,
18-
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
19-
NestedCVariadicType, ReturnTypesUseThinArrow,
18+
HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut,
19+
NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow,
2020
};
2121
use crate::parser::item::FrontMatterParsingMode;
2222
use crate::parser::{FnContext, FnParseMode};
@@ -106,6 +106,15 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
106106
impl<'a> Parser<'a> {
107107
/// Parses a type.
108108
pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> {
109+
if self.token == token::DotDotDot {
110+
// We special case this so that we don't talk about "nested C-variadics" in types.
111+
// We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about
112+
// things like `Vec<...>`.
113+
let span = self.token.span;
114+
self.bump();
115+
let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span }));
116+
return Ok(self.mk_ty(span, kind));
117+
}
109118
// Make sure deeply nested types don't overflow the stack.
110119
ensure_sufficient_stack(|| {
111120
self.parse_ty_common(

compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use std::path::PathBuf;
44

55
use rustc_errors::codes::*;
66
use rustc_errors::{Diag, IntoDiagArg};
7-
use rustc_hir as hir;
87
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
98
use rustc_hir::def_id::{DefId, LocalDefId};
109
use rustc_hir::intravisit::{self, Visitor};
11-
use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
10+
use rustc_hir::{
11+
self as hir, Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource, PatKind,
12+
};
1213
use rustc_middle::bug;
1314
use rustc_middle::hir::nested_filter;
1415
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
@@ -512,7 +513,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
512513
type_name: ty_to_string(self, ty, def_id),
513514
});
514515
}
515-
InferSourceKind::ClosureArg { insert_span, ty } => {
516+
InferSourceKind::ClosureArg { insert_span, ty, .. } => {
516517
infer_subdiags.push(SourceKindSubdiag::LetLike {
517518
span: insert_span,
518519
name: String::new(),
@@ -652,6 +653,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
652653
}),
653654
};
654655
*err.long_ty_path() = long_ty_path;
656+
if let InferSourceKind::ClosureArg { kind: PatKind::Err(_), .. } = kind {
657+
// We will have already emitted an error about this pattern.
658+
err.downgrade_to_delayed_bug();
659+
}
655660
err
656661
}
657662
}
@@ -673,6 +678,7 @@ enum InferSourceKind<'tcx> {
673678
ClosureArg {
674679
insert_span: Span,
675680
ty: Ty<'tcx>,
681+
kind: PatKind<'tcx>,
676682
},
677683
GenericArg {
678684
insert_span: Span,
@@ -1197,6 +1203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
11971203
kind: InferSourceKind::ClosureArg {
11981204
insert_span: param.pat.span.shrink_to_hi(),
11991205
ty: param_ty,
1206+
kind: param.pat.kind,
12001207
},
12011208
})
12021209
}

tests/ui/c-variadic/no-closure.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
// Check that `...` in closures is rejected.
55

66
const F: extern "C" fn(...) = |_: ...| {};
7-
//~^ ERROR C-variadic type `...` may not be nested inside another type
7+
//~^ ERROR: unexpected `...`
8+
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
89

910
fn foo() {
1011
let f = |...| {};
11-
//~^ ERROR: `..` patterns are not allowed here
12-
//~| ERROR: unexpected `...`
12+
//~^ ERROR: unexpected `...`
13+
//~| NOTE: not a valid pattern
14+
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
1315

1416
let f = |_: ...| {};
15-
//~^ ERROR C-variadic type `...` may not be nested inside another type
17+
//~^ ERROR: unexpected `...`
18+
//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
1619
f(1i64)
1720
}
Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
1-
error[E0743]: C-variadic type `...` may not be nested inside another type
1+
error: unexpected `...`
22
--> $DIR/no-closure.rs:6:35
33
|
44
LL | const F: extern "C" fn(...) = |_: ...| {};
55
| ^^^
6+
|
7+
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
68

79
error: unexpected `...`
8-
--> $DIR/no-closure.rs:10:14
10+
--> $DIR/no-closure.rs:11:14
911
|
1012
LL | let f = |...| {};
1113
| ^^^ not a valid pattern
1214
|
13-
help: for a rest pattern, use `..` instead of `...`
14-
|
15-
LL - let f = |...| {};
16-
LL + let f = |..| {};
17-
|
15+
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
1816

19-
error[E0743]: C-variadic type `...` may not be nested inside another type
20-
--> $DIR/no-closure.rs:14:17
17+
error: unexpected `...`
18+
--> $DIR/no-closure.rs:16:17
2119
|
2220
LL | let f = |_: ...| {};
2321
| ^^^
24-
25-
error: `..` patterns are not allowed here
26-
--> $DIR/no-closure.rs:10:14
27-
|
28-
LL | let f = |...| {};
29-
| ^^^
3022
|
31-
= note: only allowed in tuple, tuple struct, and slice patterns
23+
= note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
3224

33-
error: aborting due to 4 previous errors
25+
error: aborting due to 3 previous errors
3426

35-
For more information about this error, try `rustc --explain E0743`.

0 commit comments

Comments
 (0)