summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_ast_passes
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_ast_passes')
-rw-r--r--compiler/rustc_ast_passes/messages.ftl7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs129
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs30
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs30
4 files changed, 128 insertions, 68 deletions
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 2f0ac0c2b..f323bb4c2 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -239,5 +239,10 @@ ast_passes_visibility_not_permitted =
.individual_impl_items = place qualifiers on individual impl items instead
.individual_foreign_items = place qualifiers on individual foreign items instead
-ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+ast_passes_where_clause_after_type_alias = where clauses are not allowed after the type for type aliases
+ .note = see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+ .help = add `#![feature(lazy_type_alias)]` to the crate attributes to enable
+
+ast_passes_where_clause_before_type_alias = where clauses are not allowed before the type for type aliases
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+ .suggestion = move it to the end of the type declaration
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 096cea945..bd3e676da 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,6 +13,7 @@ use rustc_ast::*;
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::{
@@ -45,6 +46,7 @@ enum DisallowTildeConstContext<'a> {
struct AstValidator<'a> {
session: &'a Session,
+ features: &'a Features,
/// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod: Option<&'a Item>,
@@ -136,40 +138,42 @@ impl<'a> AstValidator<'a> {
}
}
- fn check_gat_where(
+ fn check_type_alias_where_clause_location(
&mut self,
- id: NodeId,
- before_predicates: &[WherePredicate],
- where_clauses: (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
- ) {
- if !before_predicates.is_empty() {
- let mut state = State::new();
- if !where_clauses.1.0 {
- state.space();
- state.word_space("where");
- } else {
+ ty_alias: &TyAlias,
+ ) -> Result<(), errors::WhereClauseBeforeTypeAlias> {
+ let before_predicates =
+ ty_alias.generics.where_clause.predicates.split_at(ty_alias.where_predicates_split).0;
+
+ if ty_alias.ty.is_none() || before_predicates.is_empty() {
+ return Ok(());
+ }
+
+ let mut state = State::new();
+ if !ty_alias.where_clauses.1.0 {
+ state.space();
+ state.word_space("where");
+ } else {
+ state.word_space(",");
+ }
+ let mut first = true;
+ for p in before_predicates {
+ if !first {
state.word_space(",");
}
- let mut first = true;
- for p in before_predicates.iter() {
- if !first {
- state.word_space(",");
- }
- first = false;
- state.print_where_predicate(p);
- }
- let suggestion = state.s.eof();
- self.lint_buffer.buffer_lint_with_diagnostic(
- DEPRECATED_WHERE_CLAUSE_LOCATION,
- id,
- where_clauses.0.1,
- fluent::ast_passes_deprecated_where_clause_location,
- BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
- where_clauses.1.1.shrink_to_hi(),
- suggestion,
- ),
- );
+ first = false;
+ state.print_where_predicate(p);
}
+
+ let span = ty_alias.where_clauses.0.1;
+ Err(errors::WhereClauseBeforeTypeAlias {
+ span,
+ sugg: errors::WhereClauseBeforeTypeAliasSugg {
+ left: span,
+ snippet: state.s.eof(),
+ right: ty_alias.where_clauses.1.1.shrink_to_hi(),
+ },
+ })
}
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
@@ -659,7 +663,7 @@ fn validate_generic_param_order(
GenericParamKind::Type { .. } => (ParamKindOrd::TypeOrConst, ident.to_string()),
GenericParamKind::Const { ty, .. } => {
let ty = pprust::ty_to_string(ty);
- (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty))
+ (ParamKindOrd::TypeOrConst, format!("const {ident}: {ty}"))
}
};
param_idents.push((kind, ord_kind, bounds, idx, ident));
@@ -1009,7 +1013,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
replace_span: self.ending_semi_or_hi(item.span),
});
}
- ItemKind::TyAlias(box TyAlias { defaultness, where_clauses, bounds, ty, .. }) => {
+ ItemKind::TyAlias(
+ ty_alias @ box TyAlias { defaultness, bounds, where_clauses, ty, .. },
+ ) => {
self.check_defaultness(item.span, *defaultness);
if ty.is_none() {
self.session.emit_err(errors::TyAliasWithoutBody {
@@ -1018,9 +1024,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
self.check_type_no_bounds(bounds, "this context");
- if where_clauses.1.0 {
- self.err_handler()
- .emit_err(errors::WhereAfterTypeAlias { span: where_clauses.1.1 });
+
+ if self.features.lazy_type_alias {
+ if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
+ self.err_handler().emit_err(err);
+ }
+ } else if where_clauses.1.0 {
+ self.err_handler().emit_err(errors::WhereClauseAfterTypeAlias {
+ span: where_clauses.1.1,
+ help: self.session.is_nightly_build().then_some(()),
+ });
}
}
_ => {}
@@ -1300,14 +1313,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
}
- AssocItemKind::Type(box TyAlias {
- generics,
- where_clauses,
- where_predicates_split,
- bounds,
- ty,
- ..
- }) => {
+ AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
if ty.is_none() {
self.session.emit_err(errors::AssocTypeWithoutBody {
span: item.span,
@@ -1315,18 +1321,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
self.check_type_no_bounds(bounds, "`impl`s");
- if ty.is_some() {
- self.check_gat_where(
- item.id,
- generics.where_clause.predicates.split_at(*where_predicates_split).0,
- *where_clauses,
- );
- }
}
_ => {}
}
}
+ if let AssocItemKind::Type(ty_alias) = &item.kind
+ && let Err(err) = self.check_type_alias_where_clause_location(ty_alias)
+ {
+ self.lint_buffer.buffer_lint_with_diagnostic(
+ DEPRECATED_WHERE_CLAUSE_LOCATION,
+ item.id,
+ err.span,
+ fluent::ast_passes_deprecated_where_clause_location,
+ BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(
+ err.sugg.right,
+ err.sugg.snippet,
+ ),
+ );
+ }
+
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
@@ -1462,15 +1476,12 @@ fn deny_equality_constraints(
let Some(arg) = args.args.last() else {
continue;
};
- (
- format!(", {} = {}", assoc, ty),
- arg.span().shrink_to_hi(),
- )
+ (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi())
}
_ => continue,
},
None => (
- format!("<{} = {}>", assoc, ty),
+ format!("<{assoc} = {ty}>"),
trait_segment.span().shrink_to_hi(),
),
};
@@ -1491,9 +1502,15 @@ fn deny_equality_constraints(
this.err_handler().emit_err(err);
}
-pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
+pub fn check_crate(
+ session: &Session,
+ features: &Features,
+ krate: &Crate,
+ lints: &mut LintBuffer,
+) -> bool {
let mut validator = AstValidator {
session,
+ features,
extern_mod: None,
in_trait_impl: false,
in_const_trait_impl: false,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index ab8015c4a..a6f217d47 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -496,11 +496,37 @@ pub struct FieldlessUnion {
}
#[derive(Diagnostic)]
-#[diag(ast_passes_where_after_type_alias)]
+#[diag(ast_passes_where_clause_after_type_alias)]
#[note]
-pub struct WhereAfterTypeAlias {
+pub struct WhereClauseAfterTypeAlias {
#[primary_span]
pub span: Span,
+ #[help]
+ pub help: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_where_clause_before_type_alias)]
+#[note]
+pub struct WhereClauseBeforeTypeAlias {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: WhereClauseBeforeTypeAliasSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ ast_passes_suggestion,
+ applicability = "machine-applicable",
+ style = "verbose"
+)]
+pub struct WhereClauseBeforeTypeAliasSugg {
+ #[suggestion_part(code = "")]
+ pub left: Span,
+ pub snippet: String,
+ #[suggestion_part(code = "{snippet}")]
+ pub right: Span,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b0dbc2c23..10c9c3ef1 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -218,6 +218,19 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
}
+ if !attr.is_doc_comment()
+ && attr.get_normal_item().path.segments.len() == 2
+ && attr.get_normal_item().path.segments[0].ident.name == sym::diagnostic
+ && !self.features.diagnostic_namespace
+ {
+ let msg = "`#[diagnostic]` attribute name space is experimental";
+ gate_feature_post!(
+ self,
+ diagnostic_namespace,
+ attr.get_normal_item().path.segments[0].ident.span,
+ msg
+ );
+ }
// Emit errors for non-staged-api crates.
if !self.features.staged_api {
@@ -501,10 +514,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
-pub fn check_crate(krate: &ast::Crate, sess: &Session) {
- maybe_stage_features(sess, krate);
- check_incompatible_features(sess);
- let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
+pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
+ maybe_stage_features(sess, features, krate);
+ check_incompatible_features(sess, features);
+ let mut visitor = PostExpansionVisitor { sess, features };
let spans = sess.parse_sess.gated_spans.spans.borrow();
macro_rules! gate_all {
@@ -556,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_closures, "const closures are experimental");
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");
if !visitor.features.negative_bounds {
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
@@ -586,12 +600,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
visit::walk_crate(&mut visitor, krate);
}
-fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
// checks if `#![feature]` has been used to enable any lang feature
// does not check the same for lib features unless there's at least one
// declared lang feature
if !sess.opts.unstable_features.is_nightly_build() {
- let lang_features = &sess.features_untracked().declared_lang_features;
+ let lang_features = &features.declared_lang_features;
if lang_features.len() == 0 {
return;
}
@@ -626,9 +640,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
}
}
-fn check_incompatible_features(sess: &Session) {
- let features = sess.features_untracked();
-
+fn check_incompatible_features(sess: &Session, features: &Features) {
let declared_features = features
.declared_lang_features
.iter()