Skip to content

Commit 5cf69aa

Browse files
committed
Auto merge of #30753 - pnkfelix:downgrade-29383-struct-warnings-to-errors, r=nikomatsakis
Downgrade unit struct match via S(..) warnings to errors The error signalling was introduced in #29383 It was noted as a warning-cycle-less regression in #30379 Fix #30379
2 parents d228cd3 + fa027d1 commit 5cf69aa

File tree

6 files changed

+37
-21
lines changed

6 files changed

+37
-21
lines changed

src/librustc/lint/builtin.rs

+7
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ declare_lint! {
133133
"type parameter default erroneously allowed in invalid location"
134134
}
135135

136+
declare_lint! {
137+
pub MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
138+
Warn,
139+
"unit struct or enum variant erroneously allowed to match via path::ident(..)"
140+
}
141+
136142
/// Does nothing as a lint pass, but registers some `Lint`s
137143
/// which are used by other parts of the compiler.
138144
#[derive(Copy, Clone)]
@@ -159,6 +165,7 @@ impl LintPass for HardwiredLints {
159165
TRIVIAL_NUMERIC_CASTS,
160166
PRIVATE_IN_PUBLIC,
161167
INVALID_TYPE_PARAM_DEFAULT,
168+
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
162169
CONST_ERR
163170
)
164171
}

src/librustc_lint/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
144144
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
145145

146146
add_lint_group!(sess, FUTURE_INCOMPATIBLE,
147-
PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT);
147+
PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT,
148+
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT);
148149

149150
// We have one lint pass defined specially
150151
store.register_late_pass(sess, false, box lint::GatherNodeLevels);

src/librustc_typeck/check/_match.rs

+22-16
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
1919
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
2020
use check::{check_expr_with_lvalue_pref};
2121
use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
22+
use lint;
2223
use require_same_types;
2324
use util::nodemap::FnvHashMap;
2425
use session::Session;
@@ -138,7 +139,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
138139
if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => {
139140
if let hir::PatEnum(ref path, ref subpats) = pat.node {
140141
if !(subpats.is_some() && subpats.as_ref().unwrap().is_empty()) {
141-
bad_struct_kind_err(tcx.sess, pat.span, path, false);
142+
bad_struct_kind_err(tcx.sess, pat, path, false);
142143
return;
143144
}
144145
}
@@ -590,10 +591,21 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx hir::Pat,
590591
}
591592

592593
// This function exists due to the warning "diagnostic code E0164 already used"
593-
fn bad_struct_kind_err(sess: &Session, span: Span, path: &hir::Path, is_warning: bool) {
594+
fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: bool) {
594595
let name = pprust::path_to_string(path);
595-
span_err_or_warn!(is_warning, sess, span, E0164,
596-
"`{}` does not name a tuple variant or a tuple struct", name);
596+
let msg = format!("`{}` does not name a tuple variant or a tuple struct", name);
597+
if lint {
598+
let expanded_msg =
599+
format!("{}; RFC 218 disallowed matching of unit variants or unit structs via {}(..)",
600+
msg,
601+
name);
602+
sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
603+
pat.id,
604+
pat.span,
605+
expanded_msg);
606+
} else {
607+
span_err!(sess, pat.span, E0164, "{}", msg);
608+
}
597609
}
598610

599611
pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
@@ -657,11 +669,8 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
657669
opt_ty, def, pat.span, pat.id);
658670

659671
let report_bad_struct_kind = |is_warning| {
660-
bad_struct_kind_err(tcx.sess, pat.span, path, is_warning);
661-
if is_warning {
662-
return;
663-
}
664-
672+
bad_struct_kind_err(tcx.sess, pat, path, is_warning);
673+
if is_warning { return; }
665674
fcx.write_error(pat.id);
666675
if let Some(subpats) = subpats {
667676
for pat in subpats {
@@ -699,12 +708,6 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
699708
report_bad_struct_kind(is_special_case);
700709
if !is_special_case {
701710
return
702-
} else {
703-
// Boo! Too painful to attach this to the actual warning,
704-
// it should go away at some point though.
705-
tcx.sess.span_note_without_error(pat.span,
706-
"this warning will become a HARD ERROR in a future release. \
707-
See RFC 218 for details.");
708711
}
709712
}
710713
(variant.fields
@@ -718,7 +721,10 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
718721
ty::TyStruct(struct_def, expected_substs) => {
719722
let variant = struct_def.struct_variant();
720723
if is_tuple_struct_pat && variant.kind() != ty::VariantKind::Tuple {
721-
report_bad_struct_kind(false);
724+
// Matching unit structs with tuple variant patterns (`UnitVariant(..)`)
725+
// is allowed for backward compatibility.
726+
let is_special_case = variant.kind() == ty::VariantKind::Unit;
727+
report_bad_struct_kind(is_special_case);
722728
return;
723729
}
724730
(variant.fields

src/test/compile-fail/empty-struct-unit-pat.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
// Can't use unit struct as enum pattern
1212

13+
#![feature(rustc_attrs)]
14+
// remove prior feature after warning cycle and promoting warnings to errors
1315
#![feature(braced_empty_structs)]
1416

1517
struct Empty1;
@@ -18,7 +20,9 @@ enum E {
1820
Empty2
1921
}
2022

21-
fn main() {
23+
// remove attribute after warning cycle and promoting warnings to errors
24+
#[rustc_error]
25+
fn main() { //~ ERROR: compilation successful
2226
let e1 = Empty1;
2327
let e2 = E::Empty2;
2428

@@ -27,7 +31,7 @@ fn main() {
2731
// Empty1() => () // ERROR `Empty1` does not name a tuple variant or a tuple struct
2832
// }
2933
match e1 {
30-
Empty1(..) => () //~ ERROR `Empty1` does not name a tuple variant or a tuple struct
34+
Empty1(..) => () //~ WARN `Empty1` does not name a tuple variant or a tuple struct
3135
}
3236
// Rejected by parser as yet
3337
// match e2 {

src/test/compile-fail/match-pattern-field-mismatch-2.rs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ fn main() {
2121
color::cmyk(_, _, _, _) => { }
2222
color::no_color(_) => { }
2323
//~^ ERROR this pattern has 1 field, but the corresponding variant has no fields
24-
//~^^ WARN `color::no_color` does not name a tuple variant or a tuple struct
2524
}
2625
}
2726
}

src/test/compile-fail/pattern-error-continue.rs

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ fn main() {
2626
match A::B(1, 2) {
2727
A::B(_, _, _) => (), //~ ERROR this pattern has 3 fields, but
2828
A::D(_) => (), //~ ERROR this pattern has 1 field, but
29-
//~^ WARN `A::D` does not name a tuple variant or a tuple struct
3029
_ => ()
3130
}
3231
match 'c' {

0 commit comments

Comments
 (0)