summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_passes
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_ast_passes
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_ast_passes')
-rw-r--r--compiler/rustc_ast_passes/messages.ftl22
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs188
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs46
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs25
4 files changed, 139 insertions, 142 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index f323bb4c2..43020a930 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,3 +1,7 @@
+ast_passes_anon_struct_or_union_not_allowed =
+ anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields
+ .label = anonymous {$struct_or_union} declared here
+
ast_passes_assoc_const_without_body =
associated constant in `impl` without body
.suggestion = provide a definition for the constant
@@ -113,16 +117,6 @@ ast_passes_forbidden_default =
`default` is only allowed on items in trait impls
.label = `default` because of this
-ast_passes_forbidden_let =
- `let` expressions are not supported here
- .note = only supported directly in conditions of `if` and `while` expressions
- .not_supported_or = `||` operators are not supported in let chain expressions
- .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
-
-ast_passes_forbidden_let_stable =
- expected expression, found statement (`let`)
- .note = variable declaration using `let` is a statement
-
ast_passes_forbidden_lifetime_bound =
lifetime bounds cannot be used in this context
@@ -162,6 +156,14 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
ast_passes_invalid_label =
invalid label name `{$name}`
+ast_passes_invalid_unnamed_field =
+ unnamed fields are not allowed outside of structs or unions
+ .label = unnamed field declared here
+
+ast_passes_invalid_unnamed_field_ty =
+ unnamed fields can only have struct or union types
+ .label = not a struct or union
+
ast_passes_item_underscore = `{$kind}` items in this context need a name
.label = `_` is not a valid name for this `{$kind}` item
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index bd3e676da..7bc685a54 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -14,14 +14,12 @@ use rustc_ast::{walk_list, StaticItem};
use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxIndexMap;
use rustc_feature::Features;
-use rustc_macros::Subdiagnostic;
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
};
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
-use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::spec::abi;
@@ -69,9 +67,6 @@ struct AstValidator<'a> {
/// or `Foo::Bar<impl Trait>`
is_impl_trait_banned: bool,
- /// See [ForbiddenLetReason]
- forbidden_let_reason: Option<ForbiddenLetReason>,
-
lint_buffer: &'a mut LintBuffer,
}
@@ -118,26 +113,6 @@ impl<'a> AstValidator<'a> {
self.with_tilde_const(Some(ctx), f)
}
- fn with_let_management(
- &mut self,
- forbidden_let_reason: Option<ForbiddenLetReason>,
- f: impl FnOnce(&mut Self, Option<ForbiddenLetReason>),
- ) {
- let old = mem::replace(&mut self.forbidden_let_reason, forbidden_let_reason);
- f(self, old);
- self.forbidden_let_reason = old;
- }
-
- /// Emits an error banning the `let` expression provided in the given location.
- fn ban_let_expr(&self, expr: &'a Expr, forbidden_let_reason: ForbiddenLetReason) {
- let sess = &self.session;
- if sess.opts.unstable_features.is_nightly_build() {
- sess.emit_err(errors::ForbiddenLet { span: expr.span, reason: forbidden_let_reason });
- } else {
- sess.emit_err(errors::ForbiddenLetStable { span: expr.span });
- }
- }
-
fn check_type_alias_where_clause_location(
&mut self,
ty_alias: &TyAlias,
@@ -223,10 +198,27 @@ impl<'a> AstValidator<'a> {
}
}
}
+ TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
+ walk_list!(self, visit_field_def, fields)
+ }
_ => visit::walk_ty(self, t),
}
}
+ fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
+ if let Some(ident) = field.ident &&
+ ident.name == kw::Underscore {
+ self.check_unnamed_field_ty(&field.ty, ident.span);
+ self.visit_vis(&field.vis);
+ self.visit_ident(ident);
+ self.visit_ty_common(&field.ty);
+ self.walk_ty(&field.ty);
+ walk_list!(self, visit_attribute, &field.attrs);
+ } else {
+ self.visit_field_def(field);
+ }
+ }
+
fn err_handler(&self) -> &rustc_errors::Handler {
&self.session.diagnostic()
}
@@ -264,6 +256,42 @@ impl<'a> AstValidator<'a> {
}
}
+ fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
+ if matches!(
+ &ty.kind,
+ // We already checked for `kw::Underscore` before calling this function,
+ // so skip the check
+ TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
+ // If the anonymous field contains a Path as type, we can't determine
+ // if the path is a valid struct or union, so skip the check
+ | TyKind::Path(..)
+ ) {
+ return;
+ }
+ self.err_handler().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
+ }
+
+ fn deny_anon_struct_or_union(&self, ty: &Ty) {
+ let struct_or_union = match &ty.kind {
+ TyKind::AnonStruct(..) => "struct",
+ TyKind::AnonUnion(..) => "union",
+ _ => return,
+ };
+ self.err_handler()
+ .emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
+ }
+
+ fn deny_unnamed_field(&self, field: &FieldDef) {
+ if let Some(ident) = field.ident &&
+ ident.name == kw::Underscore {
+ self.err_handler()
+ .emit_err(errors::InvalidUnnamedField {
+ span: field.span,
+ ident_span: ident.span
+ });
+ }
+ }
+
fn check_trait_fn_not_const(&self, constness: Const) {
if let Const::Yes(span) = constness {
self.session.emit_err(errors::TraitFnConst { span });
@@ -726,69 +754,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
validate_attr::check_attr(&self.session.parse_sess, attr);
}
- fn visit_expr(&mut self, expr: &'a Expr) {
- self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
- match &expr.kind {
- ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
- let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
- this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
- this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
- }
- ExprKind::If(cond, then, opt_else) => {
- this.visit_block(then);
- walk_list!(this, visit_expr, opt_else);
- this.with_let_management(None, |this, _| this.visit_expr(cond));
- return;
- }
- ExprKind::Let(..) if let Some(elem) = forbidden_let_reason => {
- this.ban_let_expr(expr, elem);
- },
- ExprKind::Match(scrutinee, arms) => {
- this.visit_expr(scrutinee);
- for arm in arms {
- this.visit_expr(&arm.body);
- this.visit_pat(&arm.pat);
- walk_list!(this, visit_attribute, &arm.attrs);
- if let Some(guard) = &arm.guard {
- this.with_let_management(None, |this, _| {
- this.visit_expr(guard)
- });
- }
- }
- }
- ExprKind::Paren(local_expr) => {
- fn has_let_expr(expr: &Expr) -> bool {
- match &expr.kind {
- ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
- ExprKind::Let(..) => true,
- _ => false,
- }
- }
- let local_reason = if has_let_expr(local_expr) {
- Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
- }
- else {
- forbidden_let_reason
- };
- this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
- }
- ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
- this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
- return;
- }
- ExprKind::While(cond, then, opt_label) => {
- walk_list!(this, visit_label, opt_label);
- this.visit_block(then);
- this.with_let_management(None, |this, _| this.visit_expr(cond));
- return;
- }
- _ => visit::walk_expr(this, expr),
- }
- });
- }
-
fn visit_ty(&mut self, ty: &'a Ty) {
self.visit_ty_common(ty);
+ self.deny_anon_struct_or_union(ty);
self.walk_ty(ty)
}
@@ -803,6 +771,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
fn visit_field_def(&mut self, field: &'a FieldDef) {
+ self.deny_unnamed_field(field);
visit::walk_field_def(self, field)
}
@@ -995,10 +964,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_mod_file_item_asciionly(item.ident);
}
}
- ItemKind::Union(vdata, ..) => {
+ ItemKind::Struct(vdata, generics) => match vdata {
+ // Duplicating the `Visitor` logic allows catching all cases
+ // of `Anonymous(Struct, Union)` outside of a field struct or union.
+ //
+ // Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
+ // encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
+ // it uses `visit_ty_common`, which doesn't contain that specific check.
+ VariantData::Struct(fields, ..) => {
+ self.visit_vis(&item.vis);
+ self.visit_ident(item.ident);
+ self.visit_generics(generics);
+ walk_list!(self, visit_struct_field_def, fields);
+ walk_list!(self, visit_attribute, &item.attrs);
+ return;
+ }
+ _ => {}
+ },
+ ItemKind::Union(vdata, generics) => {
if vdata.fields().is_empty() {
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
}
+ match vdata {
+ VariantData::Struct(fields, ..) => {
+ self.visit_vis(&item.vis);
+ self.visit_ident(item.ident);
+ self.visit_generics(generics);
+ walk_list!(self, visit_struct_field_def, fields);
+ walk_list!(self, visit_attribute, &item.attrs);
+ return;
+ }
+ _ => {}
+ }
}
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
self.check_defaultness(item.span, *defaultness);
@@ -1518,26 +1515,9 @@ pub fn check_crate(
outer_impl_trait: None,
disallow_tilde_const: None,
is_impl_trait_banned: false,
- forbidden_let_reason: Some(ForbiddenLetReason::GenericForbidden),
lint_buffer: lints,
};
visit::walk_crate(&mut validator, krate);
validator.has_proc_macro_decls
}
-
-/// Used to forbid `let` expressions in certain syntactic locations.
-#[derive(Clone, Copy, Subdiagnostic)]
-pub(crate) enum ForbiddenLetReason {
- /// `let` is not valid and the source environment is not important
- GenericForbidden,
- /// A let chain with the `||` operator
- #[note(ast_passes_not_supported_or)]
- NotSupportedOr(#[primary_span] Span),
- /// A let chain with invalid parentheses
- ///
- /// For example, `let 1 = 1 && (expr && expr)` is allowed
- /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
- #[note(ast_passes_not_supported_parentheses)]
- NotSupportedParentheses(#[primary_span] Span),
-}
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index a6f217d47..e74d94e43 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -5,28 +5,9 @@ use rustc_errors::AddToDiagnostic;
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol};
-use crate::ast_validation::ForbiddenLetReason;
use crate::fluent_generated as fluent;
#[derive(Diagnostic)]
-#[diag(ast_passes_forbidden_let)]
-#[note]
-pub struct ForbiddenLet {
- #[primary_span]
- pub span: Span,
- #[subdiagnostic]
- pub(crate) reason: ForbiddenLetReason,
-}
-
-#[derive(Diagnostic)]
-#[diag(ast_passes_forbidden_let_stable)]
-#[note]
-pub struct ForbiddenLetStable {
- #[primary_span]
- pub span: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(ast_passes_keyword_lifetime)]
pub struct KeywordLifetime {
#[primary_span]
@@ -727,3 +708,30 @@ pub struct ConstraintOnNegativeBound {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_unnamed_field_ty)]
+pub struct InvalidUnnamedFieldTy {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub ty_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_invalid_unnamed_field)]
+pub struct InvalidUnnamedField {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub ident_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_anon_struct_or_union_not_allowed)]
+pub struct AnonStructOrUnionNotAllowed {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub struct_or_union: &'static str,
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 10c9c3ef1..62dc7ae58 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -570,6 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
gate_all!(explicit_tail_calls, "`become` expression is experimental");
gate_all!(generic_const_items, "generic const items are experimental");
+ gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
@@ -577,11 +578,11 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}
}
- // All uses of `gate_all!` below this point were added in #65742,
+ // All uses of `gate_all_legacy_dont_use!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
// We emit an early future-incompatible warning for these.
// New syntax gates should go above here to get a hard error gate.
- macro_rules! gate_all {
+ macro_rules! gate_all_legacy_dont_use {
($gate:ident, $msg:literal) => {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
@@ -589,13 +590,19 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
};
}
- gate_all!(trait_alias, "trait aliases are experimental");
- gate_all!(associated_type_bounds, "associated type bounds are unstable");
- gate_all!(return_type_notation, "return type notation is experimental");
- gate_all!(decl_macro, "`macro` is experimental");
- gate_all!(box_patterns, "box pattern syntax is experimental");
- gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
- gate_all!(try_blocks, "`try` blocks are unstable");
+ gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
+ gate_all_legacy_dont_use!(associated_type_bounds, "associated type bounds are unstable");
+ // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
+ // used to be gated under associated_type_bounds, which are right above, so RTN needs to
+ // be too.
+ gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
+ gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
+ gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
+ gate_all_legacy_dont_use!(
+ exclusive_range_pattern,
+ "exclusive range pattern syntax is experimental"
+ );
+ gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
visit::walk_crate(&mut visitor, krate);
}