From 5f448c3b31bb67142742b820c92c81f1d51750c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 3 Feb 2024 00:25:18 +0100 Subject: [PATCH 1/5] Properly handle nested items during AST validation --- .../rustc_ast_passes/src/ast_validation.rs | 100 ++++++++++-------- .../impls-nested-within-fns-semantic-0.rs | 15 +++ .../impls-nested-within-fns-semantic-1.rs | 21 ++++ ...tems-nested-within-anon-consts-semantic.rs | 51 +++++++++ .../tilde-const-invalid-places-nested.rs | 39 +++++++ .../tilde-const-invalid-places-nested.stderr | 34 ++++++ 6 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 tests/ui/parser/impls-nested-within-fns-semantic-0.rs create mode 100644 tests/ui/parser/impls-nested-within-fns-semantic-1.rs create mode 100644 tests/ui/parser/items-nested-within-anon-consts-semantic.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9ea5d1ed5fa27..f0e85a75b56bf 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -73,20 +73,17 @@ struct AstValidator<'a> { /// The span of the `extern` in an `extern { ... }` block, if any. extern_mod: Option<&'a Item>, - outer_trait_or_trait_impl: Option>, - has_proc_macro_decls: bool, + outer_trait_or_trait_impl: Option>, /// Used to ban nested `impl Trait`, e.g., `impl Into`. /// Nested `impl Trait` _is_ allowed in associated type position, /// e.g., `impl Iterator`. outer_impl_trait: Option, - - disallow_tilde_const: Option>, - /// Used to ban `impl Trait` in path projections like `::Item` /// or `Foo::Bar` is_impl_trait_banned: bool, + disallow_tilde_const: Option>, lint_buffer: &'a mut LintBuffer, } @@ -134,6 +131,25 @@ impl<'a> AstValidator<'a> { self.disallow_tilde_const = old; } + fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.outer_impl_trait, outer); + f(self); + self.outer_impl_trait = old; + } + + fn in_new_context(&mut self, f: impl FnOnce(&mut Self)) { + let outer_trait_or_trait_impl = self.outer_trait_or_trait_impl.take(); + let outer_impl_trait = self.outer_impl_trait.take(); + let is_impl_trait_banned = mem::take(&mut self.is_impl_trait_banned); + let disallow_tilde_const = + mem::replace(&mut self.disallow_tilde_const, Some(DisallowTildeConstContext::Item)); + f(self); + self.disallow_tilde_const = disallow_tilde_const; + self.is_impl_trait_banned = is_impl_trait_banned; + self.outer_impl_trait = outer_impl_trait; + self.outer_trait_or_trait_impl = outer_trait_or_trait_impl; + } + fn check_type_alias_where_clause_location( &mut self, ty_alias: &TyAlias, @@ -172,12 +188,6 @@ impl<'a> AstValidator<'a> { }) } - fn with_impl_trait(&mut self, outer: Option, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.outer_impl_trait, outer); - f(self); - self.outer_impl_trait = old; - } - // Mirrors `visit::walk_ty`, but tracks relevant state. fn walk_ty(&mut self, t: &'a Ty) { match &t.kind { @@ -925,35 +935,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> { only_trait: only_trait.then_some(()), }; - self.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualImplItems, - ); - if let &Unsafe::Yes(span) = unsafety { - self.dcx().emit_err(errors::InherentImplCannotUnsafe { - span: self_ty.span, - annotation_span: span, - annotation: "unsafe", - self_ty: self_ty.span, - }); - } - if let &ImplPolarity::Negative(span) = polarity { - self.dcx().emit_err(error(span, "negative", false)); - } - if let &Defaultness::Default(def_span) = defaultness { - self.dcx().emit_err(error(def_span, "`default`", true)); - } - if let &Const::Yes(span) = constness { - self.dcx().emit_err(error(span, "`const`", true)); - } + self.with_in_trait_impl(None, |this| { + this.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualImplItems, + ); + if let &Unsafe::Yes(span) = unsafety { + this.dcx().emit_err(errors::InherentImplCannotUnsafe { + span: self_ty.span, + annotation_span: span, + annotation: "unsafe", + self_ty: self_ty.span, + }); + } + if let &ImplPolarity::Negative(span) = polarity { + this.dcx().emit_err(error(span, "negative", false)); + } + if let &Defaultness::Default(def_span) = defaultness { + this.dcx().emit_err(error(def_span, "`default`", true)); + } + if let &Const::Yes(span) = constness { + this.dcx().emit_err(error(span, "`const`", true)); + } - self.visit_vis(&item.vis); - self.visit_ident(item.ident); - self.with_tilde_const(Some(DisallowTildeConstContext::Impl(item.span)), |this| { - this.visit_generics(generics) + this.visit_vis(&item.vis); + this.visit_ident(item.ident); + this.with_tilde_const( + Some(DisallowTildeConstContext::Impl(item.span)), + |this| this.visit_generics(generics), + ); + this.visit_ty(self_ty); + walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); }); - self.visit_ty(self_ty); - walk_list!(self, visit_assoc_item, items, AssocCtxt::Impl); walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } @@ -1509,6 +1522,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { { self.visit_vis(&item.vis); self.visit_ident(item.ident); + walk_list!(self, visit_attribute, &item.attrs); let kind = FnKind::Fn( FnCtxt::Assoc(ctxt), item.ident, @@ -1529,13 +1543,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } None => DisallowTildeConstContext::InherentAssocTy(item.span), }); - self.with_tilde_const(disallowed, |this| { - this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)) - }) + self.with_tilde_const(disallowed, |this| visit::walk_assoc_item(this, item, ctxt)) } - _ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)), + _ => visit::walk_assoc_item(self, item, ctxt), } } + + fn visit_anon_const(&mut self, c: &'a AnonConst) { + self.in_new_context(|this| visit::walk_anon_const(this, c)) + } } /// When encountering an equality constraint in a `where` clause, emit an error. If the code seems diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-0.rs b/tests/ui/parser/impls-nested-within-fns-semantic-0.rs new file mode 100644 index 0000000000000..007329558bde5 --- /dev/null +++ b/tests/ui/parser/impls-nested-within-fns-semantic-0.rs @@ -0,0 +1,15 @@ +// Regression test for issue #119924. +// check-pass + +pub struct Type; + +trait Trait { + fn provided() { + impl Type { + // This visibility qualifier used to get rejected. + pub fn perform() {} + } + } +} + +fn main() {} diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-1.rs b/tests/ui/parser/impls-nested-within-fns-semantic-1.rs new file mode 100644 index 0000000000000..61634c18bcfa9 --- /dev/null +++ b/tests/ui/parser/impls-nested-within-fns-semantic-1.rs @@ -0,0 +1,21 @@ +// Regression test for issue #119924. +// check-pass +#![feature(const_trait_impl, effects)] + +pub struct Type; + +#[const_trait] +trait Trait { + fn required(); +} + +impl const Trait for () { + fn required() { + impl Type { + // This visibility qualifier used to get rejected. + pub fn perform() {} + } + } +} + +fn main() {} diff --git a/tests/ui/parser/items-nested-within-anon-consts-semantic.rs b/tests/ui/parser/items-nested-within-anon-consts-semantic.rs new file mode 100644 index 0000000000000..da37df6560579 --- /dev/null +++ b/tests/ui/parser/items-nested-within-anon-consts-semantic.rs @@ -0,0 +1,51 @@ +// Regression test for issues #119924 and #89342. +// check-pass + +struct Type; +struct Expr; + +trait Trait0 { + fn required(_: Expr<{ + impl Type { + // This visibility qualifier used to get rejected. + pub fn perform() {} + } + 0 + }>); +} + +trait Trait1 {} + +impl Trait1 for () +where + [(); { + impl Type { + // This visibility qualifier used to get rejected. + pub const STORE: Self = Self; + } + 0 + }]: +{} + +trait Trait2 {} + +fn f(_: impl Trait2<{ + // This impl-Trait used to get rejected as "nested" impl-Trait. + fn g(_: impl Sized) {} + false +}>) {} + +fn scope() { + let _: as Trait3>::Projected; +} + +trait Trait3 { type Projected; } +struct Parametrized; + +impl Trait3 for Parametrized { type Projected = (); } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.rs new file mode 100644 index 0000000000000..3f3f4b8cddfb1 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.rs @@ -0,0 +1,39 @@ +// Regression test for issue #119924. +#![feature(const_trait_impl, effects)] +#![allow(incomplete_features)] + +pub struct Type; + +#[const_trait] +trait Trait0 { + fn provided() { + impl Type { + fn perform() {} + //~^ ERROR `~const` is not allowed here + } + } +} + +struct Expr; + +#[const_trait] +trait Trait1 { + fn required(_: Expr<{ + impl Type { + fn compute() {} + //~^ ERROR `~const` is not allowed here + } + 0 + }>); +} + +#[const_trait] +trait Trait2 {} + +const fn operate>(U); + //~^ ERROR `~const` is not allowed here + 0 +}>>() {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.stderr new file mode 100644 index 0000000000000..a51d9b872d5f4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places-nested.stderr @@ -0,0 +1,34 @@ +error: `~const` is not allowed here + --> $DIR/tilde-const-invalid-places-nested.rs:11:27 + | +LL | fn perform() {} + | ^^^^^^ + | +note: this function is not `const`, so it cannot have `~const` trait bounds + --> $DIR/tilde-const-invalid-places-nested.rs:11:16 + | +LL | fn perform() {} + | ^^^^^^^ + +error: `~const` is not allowed here + --> $DIR/tilde-const-invalid-places-nested.rs:23:27 + | +LL | fn compute() {} + | ^^^^^^ + | +note: this function is not `const`, so it cannot have `~const` trait bounds + --> $DIR/tilde-const-invalid-places-nested.rs:23:16 + | +LL | fn compute() {} + | ^^^^^^^ + +error: `~const` is not allowed here + --> $DIR/tilde-const-invalid-places-nested.rs:34:17 + | +LL | struct I>(U); + | ^^^^^^ + | + = note: this item cannot have `~const` trait bounds + +error: aborting due to 3 previous errors + From e0de67f18c587375827043b8f1f8ebab5e2e6ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 5 Feb 2024 23:37:54 +0100 Subject: [PATCH 2/5] Reduce rightward drift --- .../rustc_ast_passes/src/ast_validation.rs | 242 +++++++++--------- 1 file changed, 120 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f0e85a75b56bf..6e2495425b28d 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -428,10 +428,10 @@ impl<'a> AstValidator<'a> { } fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) { - if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) { - if param.is_self() { - self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span }); - } + if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) + && param.is_self() + { + self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span }); } } @@ -560,16 +560,16 @@ impl<'a> AstValidator<'a> { return; } - if let Some(header) = fk.header() { - if let Const::Yes(const_span) = header.constness { - let mut spans = variadic_spans.clone(); - spans.push(const_span); - self.dcx().emit_err(errors::ConstAndCVariadic { - spans, - const_span, - variadic_spans: variadic_spans.clone(), - }); - } + if let Some(header) = fk.header() + && let Const::Yes(const_span) = header.constness + { + let mut spans = variadic_spans.clone(); + spans.push(const_span); + self.dcx().emit_err(errors::ConstAndCVariadic { + spans, + const_span, + variadic_spans: variadic_spans.clone(), + }); } match (fk.ctxt(), fk.header()) { @@ -795,48 +795,49 @@ fn validate_generic_param_order( }; } - if !out_of_order.is_empty() { - let mut ordered_params = "<".to_string(); - param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); - let mut first = true; - for (kind, _, bounds, _, ident) in param_idents { - if !first { - ordered_params += ", "; - } - ordered_params += &ident; - - if !bounds.is_empty() { - ordered_params += ": "; - ordered_params += &pprust::bounds_to_string(bounds); - } + if out_of_order.is_empty() { + return; + } - match kind { - GenericParamKind::Type { default: Some(default) } => { - ordered_params += " = "; - ordered_params += &pprust::ty_to_string(default); - } - GenericParamKind::Type { default: None } => (), - GenericParamKind::Lifetime => (), - GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { - ordered_params += " = "; - ordered_params += &pprust::expr_to_string(&default.value); - } - GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), - } - first = false; + let mut ordered_params = "<".to_string(); + param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i)); + let mut first = true; + for (kind, _, bounds, _, ident) in param_idents { + if !first { + ordered_params += ", "; } + ordered_params += &ident; - ordered_params += ">"; + if !bounds.is_empty() { + ordered_params += ": "; + ordered_params += &pprust::bounds_to_string(bounds); + } - for (param_ord, (max_param, spans)) in &out_of_order { - dcx.emit_err(errors::OutOfOrderParams { - spans: spans.clone(), - sugg_span: span, - param_ord, - max_param, - ordered_params: &ordered_params, - }); + match kind { + GenericParamKind::Type { default: Some(default) } => { + ordered_params += " = "; + ordered_params += &pprust::ty_to_string(default); + } + GenericParamKind::Type { default: None } => (), + GenericParamKind::Lifetime => (), + GenericParamKind::Const { ty: _, kw_span: _, default: Some(default) } => { + ordered_params += " = "; + ordered_params += &pprust::expr_to_string(&default.value); + } + GenericParamKind::Const { ty: _, kw_span: _, default: None } => (), } + first = false; + } + ordered_params += ">"; + + for (param_ord, (max_param, spans)) in &out_of_order { + dcx.emit_err(errors::OutOfOrderParams { + spans: spans.clone(), + sugg_span: span, + param_ord, + max_param, + ordered_params: &ordered_params, + }); } } @@ -1569,85 +1570,82 @@ fn deny_equality_constraints( && let [PathSegment { ident, args: None, .. }] = &path.segments[..] { for param in &generics.params { - if param.ident == *ident - && let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..] - { - // Make a new `Path` from `foo::Bar` to `Foo`. - let mut assoc_path = full_path.clone(); - // Remove `Bar` from `Foo::Bar`. - assoc_path.segments.pop(); - let len = assoc_path.segments.len() - 1; - let gen_args = args.as_deref().cloned(); - // Build ``. - let arg = AngleBracketedArg::Constraint(AssocConstraint { - id: rustc_ast::node_id::DUMMY_NODE_ID, - ident: *ident, - gen_args, - kind: AssocConstraintKind::Equality { term: predicate.rhs_ty.clone().into() }, - span: ident.span, - }); - // Add `` to `Foo`. - match &mut assoc_path.segments[len].args { - Some(args) => match args.deref_mut() { - GenericArgs::Parenthesized(_) => continue, - GenericArgs::AngleBracketed(args) => { - args.args.push(arg); - } - }, - empty_args => { - *empty_args = Some( - AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into(), - ); + if param.ident != *ident { + continue; + } + let [PathSegment { ident, args, .. }] = &full_path.segments[qself.position..] else { + continue; + }; + + // Make a new `Path` from `foo::Bar` to `Foo`. + let mut assoc_path = full_path.clone(); + // Remove `Bar` from `Foo::Bar`. + assoc_path.segments.pop(); + let gen_args = args.as_deref().cloned(); + // Build ``. + let arg = AngleBracketedArg::Constraint(AssocConstraint { + id: rustc_ast::node_id::DUMMY_NODE_ID, + ident: *ident, + gen_args, + kind: AssocConstraintKind::Equality { term: predicate.rhs_ty.clone().into() }, + span: ident.span, + }); + // Add `` to `Foo`. + match &mut assoc_path.segments.last_mut().unwrap().args { + Some(args) => match args.deref_mut() { + GenericArgs::Parenthesized(_) => continue, + GenericArgs::AngleBracketed(args) => { + args.args.push(arg); } + }, + empty_args => { + *empty_args = + Some(AngleBracketedArgs { span: ident.span, args: thin_vec![arg] }.into()); } - err.assoc = Some(errors::AssociatedSuggestion { - span: predicate.span, - ident: *ident, - param: param.ident, - path: pprust::path_to_string(&assoc_path), - }) } + err.assoc = Some(errors::AssociatedSuggestion { + span: predicate.span, + ident: *ident, + param: param.ident, + path: pprust::path_to_string(&assoc_path), + }) } } // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. - if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { - if let [potential_param, potential_assoc] = &full_path.segments[..] { - for param in &generics.params { - if param.ident == potential_param.ident { - for bound in ¶m.bounds { - if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) = - bound - { - if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] { - let assoc = pprust::path_to_string(&ast::Path::from_ident( - potential_assoc.ident, - )); - let ty = pprust::ty_to_string(&predicate.rhs_ty); - let (args, span) = match &trait_segment.args { - Some(args) => match args.deref() { - ast::GenericArgs::AngleBracketed(args) => { - let Some(arg) = args.args.last() else { - continue; - }; - (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) - } - _ => continue, - }, - None => ( - format!("<{assoc} = {ty}>"), - trait_segment.span().shrink_to_hi(), - ), + if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind + && let [potential_param, potential_assoc] = &full_path.segments[..] + { + for param in &generics.params { + if param.ident != potential_param.ident { + continue; + }; + + for bound in ¶m.bounds { + if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) = bound + && let [trait_segment] = &trait_ref.trait_ref.path.segments[..] + { + let assoc = + pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident)); + let ty = pprust::ty_to_string(&predicate.rhs_ty); + let (args, span) = match &trait_segment.args { + Some(args) => match args.deref() { + ast::GenericArgs::AngleBracketed(args) => { + let Some(arg) = args.args.last() else { + continue; }; - err.assoc2 = Some(errors::AssociatedSuggestion2 { - span, - args, - predicate: predicate.span, - trait_segment: trait_segment.ident, - potential_assoc: potential_assoc.ident, - }); + (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) } - } - } + _ => continue, + }, + None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()), + }; + err.assoc2 = Some(errors::AssociatedSuggestion2 { + span, + args, + predicate: predicate.span, + trait_segment: trait_segment.ident, + potential_assoc: potential_assoc.ident, + }); } } } From b2771c76fbbe61755a617de3c2acb79ce49b5655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 6 Feb 2024 02:36:17 +0100 Subject: [PATCH 3/5] Update doc comment about generic param order --- compiler/rustc_ast_passes/src/ast_validation.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 6e2495425b28d..f23c4974e7585 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -763,8 +763,10 @@ impl<'a> AstValidator<'a> { } } -/// Checks that generic parameters are in the correct order, -/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`) +/// Checks that generic parameters are in the correct order. +/// +/// Namely lifetimes first, followed by types and consts. +/// E.g., `<'a, T, const N: usize>` and `<'a, const N: usize, T>`. fn validate_generic_param_order( dcx: &rustc_errors::DiagCtxt, generics: &[GenericParam], From 955d8e2c5767d46782bce4686fc61904787cac5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 6 Feb 2024 03:33:00 +0100 Subject: [PATCH 4/5] Move AST validation tests to new subdirectory --- .../{ => semantic}/defaultness-invalid-places-fail-semantic.rs | 0 .../defaultness-invalid-places-fail-semantic.stderr | 0 tests/ui/parser/{ => semantic}/fn-body-optional-semantic-fail.rs | 0 .../parser/{ => semantic}/fn-body-optional-semantic-fail.stderr | 0 tests/ui/parser/{ => semantic}/fn-header-semantic-fail.rs | 0 tests/ui/parser/{ => semantic}/fn-header-semantic-fail.stderr | 0 tests/ui/parser/{ => semantic}/foreign-const-semantic-fail.rs | 0 tests/ui/parser/{ => semantic}/foreign-const-semantic-fail.stderr | 0 tests/ui/parser/{ => semantic}/foreign-static-semantic-fail.rs | 0 .../ui/parser/{ => semantic}/foreign-static-semantic-fail.stderr | 0 tests/ui/parser/{ => semantic}/foreign-ty-semantic-fail.rs | 0 tests/ui/parser/{ => semantic}/foreign-ty-semantic-fail.stderr | 0 tests/ui/parser/{ => semantic}/impl-item-const-semantic-fail.rs | 0 .../ui/parser/{ => semantic}/impl-item-const-semantic-fail.stderr | 0 .../parser/{ => semantic}/impl-item-fn-no-body-semantic-fail.rs | 0 .../{ => semantic}/impl-item-fn-no-body-semantic-fail.stderr | 0 .../parser/{ => semantic}/impl-item-type-no-body-semantic-fail.rs | 0 .../{ => semantic}/impl-item-type-no-body-semantic-fail.stderr | 0 .../parser/{ => semantic}/impls-nested-within-fns-semantic-0.rs | 0 .../parser/{ => semantic}/impls-nested-within-fns-semantic-1.rs | 0 .../{ => semantic}/item-free-const-no-body-semantic-fail.rs | 0 .../{ => semantic}/item-free-const-no-body-semantic-fail.stderr | 0 .../{ => semantic}/item-free-static-no-body-semantic-fail.rs | 0 .../{ => semantic}/item-free-static-no-body-semantic-fail.stderr | 0 .../parser/{ => semantic}/item-free-type-bounds-semantic-fail.rs | 0 .../{ => semantic}/item-free-type-bounds-semantic-fail.stderr | 0 .../{ => semantic}/items-nested-within-anon-consts-semantic.rs | 0 tests/ui/parser/{ => semantic}/self-param-semantic-fail.rs | 0 tests/ui/parser/{ => semantic}/self-param-semantic-fail.stderr | 0 .../parser/{ => semantic}/variadic-ffi-semantic-restrictions.rs | 0 .../{ => semantic}/variadic-ffi-semantic-restrictions.stderr | 0 31 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/parser/{ => semantic}/defaultness-invalid-places-fail-semantic.rs (100%) rename tests/ui/parser/{ => semantic}/defaultness-invalid-places-fail-semantic.stderr (100%) rename tests/ui/parser/{ => semantic}/fn-body-optional-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/fn-body-optional-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/fn-header-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/fn-header-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/foreign-const-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/foreign-const-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/foreign-static-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/foreign-static-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/foreign-ty-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/foreign-ty-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/impl-item-const-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/impl-item-const-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/impl-item-fn-no-body-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/impl-item-fn-no-body-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/impl-item-type-no-body-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/impl-item-type-no-body-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/impls-nested-within-fns-semantic-0.rs (100%) rename tests/ui/parser/{ => semantic}/impls-nested-within-fns-semantic-1.rs (100%) rename tests/ui/parser/{ => semantic}/item-free-const-no-body-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/item-free-const-no-body-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/item-free-static-no-body-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/item-free-static-no-body-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/item-free-type-bounds-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/item-free-type-bounds-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/items-nested-within-anon-consts-semantic.rs (100%) rename tests/ui/parser/{ => semantic}/self-param-semantic-fail.rs (100%) rename tests/ui/parser/{ => semantic}/self-param-semantic-fail.stderr (100%) rename tests/ui/parser/{ => semantic}/variadic-ffi-semantic-restrictions.rs (100%) rename tests/ui/parser/{ => semantic}/variadic-ffi-semantic-restrictions.stderr (100%) diff --git a/tests/ui/parser/defaultness-invalid-places-fail-semantic.rs b/tests/ui/parser/semantic/defaultness-invalid-places-fail-semantic.rs similarity index 100% rename from tests/ui/parser/defaultness-invalid-places-fail-semantic.rs rename to tests/ui/parser/semantic/defaultness-invalid-places-fail-semantic.rs diff --git a/tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr b/tests/ui/parser/semantic/defaultness-invalid-places-fail-semantic.stderr similarity index 100% rename from tests/ui/parser/defaultness-invalid-places-fail-semantic.stderr rename to tests/ui/parser/semantic/defaultness-invalid-places-fail-semantic.stderr diff --git a/tests/ui/parser/fn-body-optional-semantic-fail.rs b/tests/ui/parser/semantic/fn-body-optional-semantic-fail.rs similarity index 100% rename from tests/ui/parser/fn-body-optional-semantic-fail.rs rename to tests/ui/parser/semantic/fn-body-optional-semantic-fail.rs diff --git a/tests/ui/parser/fn-body-optional-semantic-fail.stderr b/tests/ui/parser/semantic/fn-body-optional-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/fn-body-optional-semantic-fail.stderr rename to tests/ui/parser/semantic/fn-body-optional-semantic-fail.stderr diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/semantic/fn-header-semantic-fail.rs similarity index 100% rename from tests/ui/parser/fn-header-semantic-fail.rs rename to tests/ui/parser/semantic/fn-header-semantic-fail.rs diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/semantic/fn-header-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/fn-header-semantic-fail.stderr rename to tests/ui/parser/semantic/fn-header-semantic-fail.stderr diff --git a/tests/ui/parser/foreign-const-semantic-fail.rs b/tests/ui/parser/semantic/foreign-const-semantic-fail.rs similarity index 100% rename from tests/ui/parser/foreign-const-semantic-fail.rs rename to tests/ui/parser/semantic/foreign-const-semantic-fail.rs diff --git a/tests/ui/parser/foreign-const-semantic-fail.stderr b/tests/ui/parser/semantic/foreign-const-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/foreign-const-semantic-fail.stderr rename to tests/ui/parser/semantic/foreign-const-semantic-fail.stderr diff --git a/tests/ui/parser/foreign-static-semantic-fail.rs b/tests/ui/parser/semantic/foreign-static-semantic-fail.rs similarity index 100% rename from tests/ui/parser/foreign-static-semantic-fail.rs rename to tests/ui/parser/semantic/foreign-static-semantic-fail.rs diff --git a/tests/ui/parser/foreign-static-semantic-fail.stderr b/tests/ui/parser/semantic/foreign-static-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/foreign-static-semantic-fail.stderr rename to tests/ui/parser/semantic/foreign-static-semantic-fail.stderr diff --git a/tests/ui/parser/foreign-ty-semantic-fail.rs b/tests/ui/parser/semantic/foreign-ty-semantic-fail.rs similarity index 100% rename from tests/ui/parser/foreign-ty-semantic-fail.rs rename to tests/ui/parser/semantic/foreign-ty-semantic-fail.rs diff --git a/tests/ui/parser/foreign-ty-semantic-fail.stderr b/tests/ui/parser/semantic/foreign-ty-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/foreign-ty-semantic-fail.stderr rename to tests/ui/parser/semantic/foreign-ty-semantic-fail.stderr diff --git a/tests/ui/parser/impl-item-const-semantic-fail.rs b/tests/ui/parser/semantic/impl-item-const-semantic-fail.rs similarity index 100% rename from tests/ui/parser/impl-item-const-semantic-fail.rs rename to tests/ui/parser/semantic/impl-item-const-semantic-fail.rs diff --git a/tests/ui/parser/impl-item-const-semantic-fail.stderr b/tests/ui/parser/semantic/impl-item-const-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/impl-item-const-semantic-fail.stderr rename to tests/ui/parser/semantic/impl-item-const-semantic-fail.stderr diff --git a/tests/ui/parser/impl-item-fn-no-body-semantic-fail.rs b/tests/ui/parser/semantic/impl-item-fn-no-body-semantic-fail.rs similarity index 100% rename from tests/ui/parser/impl-item-fn-no-body-semantic-fail.rs rename to tests/ui/parser/semantic/impl-item-fn-no-body-semantic-fail.rs diff --git a/tests/ui/parser/impl-item-fn-no-body-semantic-fail.stderr b/tests/ui/parser/semantic/impl-item-fn-no-body-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/impl-item-fn-no-body-semantic-fail.stderr rename to tests/ui/parser/semantic/impl-item-fn-no-body-semantic-fail.stderr diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.rs b/tests/ui/parser/semantic/impl-item-type-no-body-semantic-fail.rs similarity index 100% rename from tests/ui/parser/impl-item-type-no-body-semantic-fail.rs rename to tests/ui/parser/semantic/impl-item-type-no-body-semantic-fail.rs diff --git a/tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/tests/ui/parser/semantic/impl-item-type-no-body-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/impl-item-type-no-body-semantic-fail.stderr rename to tests/ui/parser/semantic/impl-item-type-no-body-semantic-fail.stderr diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-0.rs b/tests/ui/parser/semantic/impls-nested-within-fns-semantic-0.rs similarity index 100% rename from tests/ui/parser/impls-nested-within-fns-semantic-0.rs rename to tests/ui/parser/semantic/impls-nested-within-fns-semantic-0.rs diff --git a/tests/ui/parser/impls-nested-within-fns-semantic-1.rs b/tests/ui/parser/semantic/impls-nested-within-fns-semantic-1.rs similarity index 100% rename from tests/ui/parser/impls-nested-within-fns-semantic-1.rs rename to tests/ui/parser/semantic/impls-nested-within-fns-semantic-1.rs diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.rs b/tests/ui/parser/semantic/item-free-const-no-body-semantic-fail.rs similarity index 100% rename from tests/ui/parser/item-free-const-no-body-semantic-fail.rs rename to tests/ui/parser/semantic/item-free-const-no-body-semantic-fail.rs diff --git a/tests/ui/parser/item-free-const-no-body-semantic-fail.stderr b/tests/ui/parser/semantic/item-free-const-no-body-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/item-free-const-no-body-semantic-fail.stderr rename to tests/ui/parser/semantic/item-free-const-no-body-semantic-fail.stderr diff --git a/tests/ui/parser/item-free-static-no-body-semantic-fail.rs b/tests/ui/parser/semantic/item-free-static-no-body-semantic-fail.rs similarity index 100% rename from tests/ui/parser/item-free-static-no-body-semantic-fail.rs rename to tests/ui/parser/semantic/item-free-static-no-body-semantic-fail.rs diff --git a/tests/ui/parser/item-free-static-no-body-semantic-fail.stderr b/tests/ui/parser/semantic/item-free-static-no-body-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/item-free-static-no-body-semantic-fail.stderr rename to tests/ui/parser/semantic/item-free-static-no-body-semantic-fail.stderr diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.rs b/tests/ui/parser/semantic/item-free-type-bounds-semantic-fail.rs similarity index 100% rename from tests/ui/parser/item-free-type-bounds-semantic-fail.rs rename to tests/ui/parser/semantic/item-free-type-bounds-semantic-fail.rs diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr b/tests/ui/parser/semantic/item-free-type-bounds-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/item-free-type-bounds-semantic-fail.stderr rename to tests/ui/parser/semantic/item-free-type-bounds-semantic-fail.stderr diff --git a/tests/ui/parser/items-nested-within-anon-consts-semantic.rs b/tests/ui/parser/semantic/items-nested-within-anon-consts-semantic.rs similarity index 100% rename from tests/ui/parser/items-nested-within-anon-consts-semantic.rs rename to tests/ui/parser/semantic/items-nested-within-anon-consts-semantic.rs diff --git a/tests/ui/parser/self-param-semantic-fail.rs b/tests/ui/parser/semantic/self-param-semantic-fail.rs similarity index 100% rename from tests/ui/parser/self-param-semantic-fail.rs rename to tests/ui/parser/semantic/self-param-semantic-fail.rs diff --git a/tests/ui/parser/self-param-semantic-fail.stderr b/tests/ui/parser/semantic/self-param-semantic-fail.stderr similarity index 100% rename from tests/ui/parser/self-param-semantic-fail.stderr rename to tests/ui/parser/semantic/self-param-semantic-fail.stderr diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/semantic/variadic-ffi-semantic-restrictions.rs similarity index 100% rename from tests/ui/parser/variadic-ffi-semantic-restrictions.rs rename to tests/ui/parser/semantic/variadic-ffi-semantic-restrictions.rs diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/semantic/variadic-ffi-semantic-restrictions.stderr similarity index 100% rename from tests/ui/parser/variadic-ffi-semantic-restrictions.stderr rename to tests/ui/parser/semantic/variadic-ffi-semantic-restrictions.stderr From d5765c897c1cb5943351638cf9858aa2391e4979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 6 Feb 2024 04:07:40 +0100 Subject: [PATCH 5/5] Bundle some fields of AstValidator in a context To ensure that `in_new_context` sets resets all "important" fields. --- .../rustc_ast_passes/src/ast_validation.rs | 63 ++++++++++++------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f23c4974e7585..9b589a185c30c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -36,6 +36,29 @@ enum SelfSemantic { No, } +struct Context<'a> { + outer_trait_or_trait_impl: Option>, + /// Used to ban nested `impl Trait`, e.g., `impl Into`. + /// Nested `impl Trait` _is_ allowed in associated type position, + /// e.g., `impl Iterator`. + outer_impl_trait: Option, + /// Used to ban `impl Trait` in path projections like `::Item` + /// or `Foo::Bar` + is_impl_trait_banned: bool, + disallow_tilde_const: Option>, +} + +impl Default for Context<'_> { + fn default() -> Self { + Self { + outer_trait_or_trait_impl: None, + outer_impl_trait: None, + is_impl_trait_banned: false, + disallow_tilde_const: Some(DisallowTildeConstContext::Item), + } + } +} + /// What is the context that prevents using `~const`? // FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're // almost identical. This gets rid of an abstraction layer which might be considered bad. @@ -75,15 +98,7 @@ struct AstValidator<'a> { has_proc_macro_decls: bool, - outer_trait_or_trait_impl: Option>, - /// Used to ban nested `impl Trait`, e.g., `impl Into`. - /// Nested `impl Trait` _is_ allowed in associated type position, - /// e.g., `impl Iterator`. - outer_impl_trait: Option, - /// Used to ban `impl Trait` in path projections like `::Item` - /// or `Foo::Bar` - is_impl_trait_banned: bool, - disallow_tilde_const: Option>, + context: Context<'a>, lint_buffer: &'a mut LintBuffer, } @@ -138,16 +153,9 @@ impl<'a> AstValidator<'a> { } fn in_new_context(&mut self, f: impl FnOnce(&mut Self)) { - let outer_trait_or_trait_impl = self.outer_trait_or_trait_impl.take(); - let outer_impl_trait = self.outer_impl_trait.take(); - let is_impl_trait_banned = mem::take(&mut self.is_impl_trait_banned); - let disallow_tilde_const = - mem::replace(&mut self.disallow_tilde_const, Some(DisallowTildeConstContext::Item)); + let context = mem::take(&mut self.context); f(self); - self.disallow_tilde_const = disallow_tilde_const; - self.is_impl_trait_banned = is_impl_trait_banned; - self.outer_impl_trait = outer_impl_trait; - self.outer_trait_or_trait_impl = outer_trait_or_trait_impl; + self.context = context; } fn check_type_alias_where_clause_location( @@ -763,6 +771,20 @@ impl<'a> AstValidator<'a> { } } +impl<'a> std::ops::Deref for AstValidator<'a> { + type Target = Context<'a>; + + fn deref(&self) -> &Self::Target { + &self.context + } +} + +impl<'a> std::ops::DerefMut for AstValidator<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.context + } +} + /// Checks that generic parameters are in the correct order. /// /// Namely lifetimes first, followed by types and consts. @@ -1665,11 +1687,8 @@ pub fn check_crate( session, features, extern_mod: None, - outer_trait_or_trait_impl: None, has_proc_macro_decls: false, - outer_impl_trait: None, - disallow_tilde_const: Some(DisallowTildeConstContext::Item), - is_impl_trait_banned: false, + context: Context::default(), lint_buffer: lints, }; visit::walk_crate(&mut validator, krate);