|
1 | 1 | use rustc_ast as ast;
|
2 | 2 | use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
3 | 3 | use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
|
4 |
| -use rustc_ast::{PatKind, RangeEnd}; |
| 4 | +use rustc_ast::{PatKind, RangeEnd, VariantData}; |
5 | 5 | use rustc_errors::struct_span_err;
|
6 | 6 | use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
|
7 | 7 | use rustc_feature::{Features, GateIssue};
|
8 |
| -use rustc_session::parse::feature_err_issue; |
| 8 | +use rustc_session::parse::{feature_err, feature_err_issue}; |
9 | 9 | use rustc_session::Session;
|
10 | 10 | use rustc_span::source_map::Spanned;
|
11 | 11 | use rustc_span::symbol::sym;
|
@@ -218,6 +218,46 @@ impl<'a> PostExpansionVisitor<'a> {
|
218 | 218 | }
|
219 | 219 | }
|
220 | 220 |
|
| 221 | + fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { |
| 222 | + let has_fields = variants.iter().any(|variant| match variant.data { |
| 223 | + VariantData::Tuple(..) | VariantData::Struct(..) => true, |
| 224 | + VariantData::Unit(..) => false, |
| 225 | + }); |
| 226 | + |
| 227 | + let discriminant_spans = variants |
| 228 | + .iter() |
| 229 | + .filter(|variant| match variant.data { |
| 230 | + VariantData::Tuple(..) | VariantData::Struct(..) => false, |
| 231 | + VariantData::Unit(..) => true, |
| 232 | + }) |
| 233 | + .filter_map(|variant| variant.disr_expr.as_ref().map(|c| c.value.span)) |
| 234 | + .collect::<Vec<_>>(); |
| 235 | + |
| 236 | + if !discriminant_spans.is_empty() && has_fields { |
| 237 | + let mut err = feature_err( |
| 238 | + &self.sess.parse_sess, |
| 239 | + sym::arbitrary_enum_discriminant, |
| 240 | + discriminant_spans.clone(), |
| 241 | + "custom discriminant values are not allowed in enums with tuple or struct variants", |
| 242 | + ); |
| 243 | + for sp in discriminant_spans { |
| 244 | + err.span_label(sp, "disallowed custom discriminant"); |
| 245 | + } |
| 246 | + for variant in variants.iter() { |
| 247 | + match &variant.data { |
| 248 | + VariantData::Struct(..) => { |
| 249 | + err.span_label(variant.span, "struct variant defined here"); |
| 250 | + } |
| 251 | + VariantData::Tuple(..) => { |
| 252 | + err.span_label(variant.span, "tuple variant defined here"); |
| 253 | + } |
| 254 | + VariantData::Unit(..) => {} |
| 255 | + } |
| 256 | + } |
| 257 | + err.emit(); |
| 258 | + } |
| 259 | + } |
| 260 | + |
221 | 261 | fn check_gat(&self, generics: &ast::Generics, span: Span) {
|
222 | 262 | if !generics.params.is_empty() {
|
223 | 263 | gate_feature_post!(
|
@@ -362,6 +402,26 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
362 | 402 | }
|
363 | 403 | }
|
364 | 404 |
|
| 405 | + ast::ItemKind::Enum(ast::EnumDef { ref variants, .. }, ..) => { |
| 406 | + for variant in variants { |
| 407 | + match (&variant.data, &variant.disr_expr) { |
| 408 | + (ast::VariantData::Unit(..), _) => {} |
| 409 | + (_, Some(disr_expr)) => gate_feature_post!( |
| 410 | + &self, |
| 411 | + arbitrary_enum_discriminant, |
| 412 | + disr_expr.value.span, |
| 413 | + "discriminants on non-unit variants are experimental" |
| 414 | + ), |
| 415 | + _ => {} |
| 416 | + } |
| 417 | + } |
| 418 | + |
| 419 | + let has_feature = self.features.arbitrary_enum_discriminant; |
| 420 | + if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { |
| 421 | + self.maybe_report_invalid_custom_discriminants(&variants); |
| 422 | + } |
| 423 | + } |
| 424 | + |
365 | 425 | ast::ItemKind::Impl(box ast::ImplKind {
|
366 | 426 | polarity, defaultness, ref of_trait, ..
|
367 | 427 | }) => {
|
|
0 commit comments