diff options
88 files changed, 1027 insertions, 345 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3496cfc38c8..9a9c769fd7c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2481,15 +2481,6 @@ pub enum Const { No, } -impl From<BoundConstness> for Const { - fn from(constness: BoundConstness) -> Self { - match constness { - BoundConstness::Maybe(span) => Self::Yes(span), - BoundConstness::Never => Self::No, - } - } -} - /// Item defaultness. /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532). #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] @@ -2543,6 +2534,8 @@ impl BoundPolarity { pub enum BoundConstness { /// `Type: Trait` Never, + /// `Type: const Trait` + Always(Span), /// `Type: ~const Trait` Maybe(Span), } @@ -2551,6 +2544,7 @@ impl BoundConstness { pub fn as_str(self) -> &'static str { match self { Self::Never => "", + Self::Always(_) => "const", Self::Maybe(_) => "~const", } } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index b0cd2ec9815..d62462b1ae3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -528,15 +528,6 @@ impl Token { } } - /// Returns `true` if the token can appear at the start of a generic bound. - pub fn can_begin_bound(&self) -> bool { - self.is_path_start() - || self.is_lifetime() - || self.is_keyword(kw::For) - || self == &Question - || self == &OpenDelim(Delimiter::Parenthesis) - } - /// Returns `true` if the token can appear at the start of an item. pub fn can_begin_item(&self) -> bool { match self.kind { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b70b9356226..3848f3b7782 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = self.lower_generics(ast_generics, *constness, id, &itctx, |this| { + let constness = match *constness { + Const::Yes(span) => BoundConstness::Maybe(span), + Const::No => BoundConstness::Never, + }; + let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( - *constness, + constness, trait_ref, &ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b4c27c29aa7..92fd29c47af 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1349,7 +1349,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: t.span, }, itctx, - ast::Const::No, + ast::BoundConstness::Never, ); let bounds = this.arena.alloc_from_iter([bound]); let lifetime_bound = this.elided_dyn_bound(t.span); @@ -1460,7 +1460,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { polarity: BoundPolarity::Positive | BoundPolarity::Negative(_), constness, }, - ) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())), + ) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)), // We can safely ignore constness here, since AST validation // will take care of invalid modifier combinations. GenericBound::Trait( @@ -2199,7 +2199,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_ref( &mut self, - constness: ast::Const, + constness: ast::BoundConstness, p: &TraitRef, itctx: &ImplTraitContext, ) -> hir::TraitRef<'hir> { @@ -2222,7 +2222,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, p: &PolyTraitRef, itctx: &ImplTraitContext, - constness: ast::Const, + constness: ast::BoundConstness, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); @@ -2347,9 +2347,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, modifiers: TraitBoundModifiers, ) -> hir::TraitBoundModifier { + // Invalid modifier combinations will cause an error during AST validation. + // Arbitrarily pick a placeholder for them to make compilation proceed. match (modifiers.constness, modifiers.polarity) { (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None, - (BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, + (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, (BoundConstness::Never, BoundPolarity::Negative(_)) => { if self.tcx.features().negative_bounds { hir::TraitBoundModifier::Negative @@ -2357,15 +2359,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TraitBoundModifier::None } } - (BoundConstness::Maybe(_), BoundPolarity::Positive) => { - hir::TraitBoundModifier::MaybeConst - } - // Invalid modifier combinations will cause an error during AST validation. - // Arbitrarily pick a placeholder for compilation to proceed. - (BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe, - (BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => { - hir::TraitBoundModifier::MaybeConst - } + (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const, + (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst, } } @@ -2583,45 +2578,62 @@ struct GenericArgsCtor<'hir> { } impl<'hir> GenericArgsCtor<'hir> { - fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) { + fn push_constness( + &mut self, + lcx: &mut LoweringContext<'_, 'hir>, + constness: ast::BoundConstness, + ) { if !lcx.tcx.features().effects { return; } - // if bound is non-const, don't add host effect param - let ast::Const::Yes(span) = constness else { return }; + let (span, body) = match constness { + BoundConstness::Never => return, + BoundConstness::Always(span) => { + let span = lcx.lower_span(span); - let span = lcx.lower_span(span); + let body = hir::ExprKind::Lit( + lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }), + ); - let id = lcx.next_node_id(); - let hir_id = lcx.next_id(); + (span, body) + } + BoundConstness::Maybe(span) => { + let span = lcx.lower_span(span); - let Some(host_param_id) = lcx.host_param_id else { - lcx.dcx().span_delayed_bug( - span, - "no host param id for call in const yet no errors reported", - ); - return; - }; + let Some(host_param_id) = lcx.host_param_id else { + lcx.dcx().span_delayed_bug( + span, + "no host param id for call in const yet no errors reported", + ); + return; + }; - let body = lcx.lower_body(|lcx| { - (&[], { let hir_id = lcx.next_id(); let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id()); - let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved( + let body = hir::ExprKind::Path(hir::QPath::Resolved( None, lcx.arena.alloc(hir::Path { span, res, - segments: arena_vec![lcx; hir::PathSegment::new(Ident { - name: sym::host, - span, - }, hir_id, res)], + segments: arena_vec![ + lcx; + hir::PathSegment::new( + Ident { name: sym::host, span }, + hir_id, + res + ) + ], }), )); - lcx.expr(span, expr_kind) - }) - }); + + (span, body) + } + }; + let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body))); + + let id = lcx.next_node_id(); + let hir_id = lcx.next_id(); let def_id = lcx.create_def( lcx.current_hir_id_owner.def_id, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 130eb3521c3..c679ee56fcd 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, itctx: &ImplTraitContext, // constness of the impl/bound if this is a trait path - constness: Option<ast::Const>, + constness: Option<ast::BoundConstness>, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); @@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: &ImplTraitContext, - constness: Option<ast::Const>, + constness: Option<ast::BoundConstness>, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment); let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() { diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index ea3cd3e4bee..b5612c1820d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi .const = `const` because of this .variadic = C-variadic because of this +ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types + ast_passes_const_without_body = free constant item without body .suggestion = provide a definition for the constant diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3600e4960af..bc5cf463f12 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1207,6 +1207,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => { self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span }); } + (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => { + self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span }); + } (_, BoundConstness::Maybe(span), BoundPolarity::Positive) if let Some(reason) = &self.disallow_tilde_const => { @@ -1237,8 +1240,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ( _, - BoundConstness::Maybe(_), - BoundPolarity::Maybe(_) | BoundPolarity::Negative(_), + BoundConstness::Always(_) | BoundConstness::Maybe(_), + BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), ) => { self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { span: bound.span(), diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index a5b842b320e..0cec4374be2 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -541,6 +541,13 @@ pub struct OptionalTraitObject { } #[derive(Diagnostic)] +#[diag(ast_passes_const_bound_trait_object)] +pub struct ConstBoundTraitObject { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub struct TildeConstDisallowed { #[primary_span] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 12d37cf5a7a..f4b424259de 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1096,14 +1096,22 @@ impl<'a> State<'a> { ast::StmtKind::Item(item) => self.print_item(item), ast::StmtKind::Expr(expr) => { self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false, FixupContext::default()); + self.print_expr_outer_attr_style( + expr, + false, + FixupContext { stmt: true, ..FixupContext::default() }, + ); if classify::expr_requires_semi_to_be_stmt(expr) { self.word(";"); } } ast::StmtKind::Semi(expr) => { self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false, FixupContext::default()); + self.print_expr_outer_attr_style( + expr, + false, + FixupContext { stmt: true, ..FixupContext::default() }, + ); self.word(";"); } ast::StmtKind::Empty => { @@ -1155,7 +1163,11 @@ impl<'a> State<'a> { ast::StmtKind::Expr(expr) if i == blk.stmts.len() - 1 => { self.maybe_print_comment(st.span.lo()); self.space_if_not_bol(); - self.print_expr_outer_attr_style(expr, false, FixupContext::default()); + self.print_expr_outer_attr_style( + expr, + false, + FixupContext { stmt: true, ..FixupContext::default() }, + ); self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi())); } _ => self.print_stmt(st), @@ -1561,7 +1573,7 @@ impl<'a> State<'a> { GenericBound::Trait(tref, modifier) => { match modifier.constness { ast::BoundConstness::Never => {} - ast::BoundConstness::Maybe(_) => { + ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => { self.word_space(modifier.constness.as_str()); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index f868beec812..ff154a009ed 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -4,6 +4,7 @@ use ast::ForLoopKind; use itertools::{Itertools, Position}; use rustc_ast::ptr::P; use rustc_ast::token; +use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::{self as ast, BlockCheckMode}; @@ -15,6 +16,61 @@ use std::fmt::Write; #[derive(Copy, Clone, Debug)] pub(crate) struct FixupContext { + /// Print expression such that it can be parsed back as a statement + /// consisting of the original expression. + /// + /// The effect of this is for binary operators in statement position to set + /// `leftmost_subexpression_in_stmt` when printing their left-hand operand. + /// + /// ```ignore (illustrative) + /// (match x {}) - 1; // match needs parens when LHS of binary operator + /// + /// match x {}; // not when its own statement + /// ``` + pub stmt: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// (match x {}) - 1; // subexpression needs parens + /// + /// let _ = match x {} - 1; // no parens + /// ``` + /// + /// There are 3 distinguishable contexts in which `print_expr` might be + /// called with the expression `$match` as its argument, where `$match` + /// represents an expression of kind `ExprKind::Match`: + /// + /// - stmt=false leftmost_subexpression_in_stmt=false + /// + /// Example: `let _ = $match - 1;` + /// + /// No parentheses required. + /// + /// - stmt=false leftmost_subexpression_in_stmt=true + /// + /// Example: `$match - 1;` + /// + /// Must parenthesize `($match)`, otherwise parsing back the output as a + /// statement would terminate the statement after the closing brace of + /// the match, parsing `-1;` as a separate statement. + /// + /// - stmt=true leftmost_subexpression_in_stmt=false + /// + /// Example: `$match;` + /// + /// No parentheses required. + pub leftmost_subexpression_in_stmt: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// if let _ = (Struct {}) {} // needs parens + /// + /// match () { + /// () if let _ = Struct {} => {} // no parens + /// } + /// ``` pub parenthesize_exterior_struct_lit: bool, } @@ -22,7 +78,11 @@ pub(crate) struct FixupContext { /// in a targetted fashion where needed. impl Default for FixupContext { fn default() -> Self { - FixupContext { parenthesize_exterior_struct_lit: false } + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + parenthesize_exterior_struct_lit: false, + } } } @@ -76,7 +136,8 @@ impl<'a> State<'a> { /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in /// `if cond { ... }`. fn print_expr_as_cond(&mut self, expr: &ast::Expr) { - let fixup = FixupContext { parenthesize_exterior_struct_lit: true }; + let fixup = + FixupContext { parenthesize_exterior_struct_lit: true, ..FixupContext::default() }; self.print_expr_cond_paren(expr, Self::cond_needs_par(expr), fixup) } @@ -99,26 +160,25 @@ impl<'a> State<'a> { &mut self, expr: &ast::Expr, needs_par: bool, - fixup: FixupContext, + mut fixup: FixupContext, ) { if needs_par { self.popen(); + + // If we are surrounding the whole cond in parentheses, such as: + // + // if (return Struct {}) {} + // + // then there is no need for parenthesizing the individual struct + // expressions within. On the other hand if the whole cond is not + // parenthesized, then print_expr must parenthesize exterior struct + // literals. + // + // if x == (Struct {}) {} + // + fixup = FixupContext::default(); } - // If we are surrounding the whole cond in parentheses, such as: - // - // if (return Struct {}) {} - // - // then there is no need for parenthesizing the individual struct - // expressions within. On the other hand if the whole cond is not - // parenthesized, then print_expr must parenthesize exterior struct - // literals. - // - // if x == (Struct {}) {} - // - let fixup = FixupContext { - parenthesize_exterior_struct_lit: fixup.parenthesize_exterior_struct_lit && !needs_par, - }; self.print_expr(expr, fixup); if needs_par { @@ -234,7 +294,32 @@ impl<'a> State<'a> { _ => parser::PREC_POSTFIX, }; - self.print_expr_maybe_paren(func, prec, fixup); + // Independent of parenthesization related to precedence, we must + // parenthesize `func` if this is a statement context in which without + // parentheses, a statement boundary would occur inside `func` or + // immediately after `func`. + // + // Suppose `func` represents `match () { _ => f }`. We must produce: + // + // (match () { _ => f })(); + // + // instead of: + // + // match () { _ => f } (); + // + // because the latter is valid syntax but with the incorrect meaning. + // It's a match-expression followed by tuple-expression, not a function + // call. + self.print_expr_maybe_paren( + func, + prec, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); + self.print_call_post(args) } @@ -245,7 +330,17 @@ impl<'a> State<'a> { base_args: &[P<ast::Expr>], fixup: FixupContext, ) { + // Unlike in `print_expr_call`, no change to fixup here because + // statement boundaries never occur in front of a `.` (or `?`) token. + // + // match () { _ => f }.method(); + // + // Parenthesizing only for precedence and not with regard to statement + // boundaries, `$receiver.method()` can be parsed back as a statement + // containing an expression if and only if `$receiver` can be parsed as + // a statement containing an expression. self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX, fixup); + self.word("."); self.print_ident(segment.ident); if let Some(args) = &segment.args { @@ -289,22 +384,36 @@ impl<'a> State<'a> { (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { parser::PREC_FORCE_PAREN } - // For a binary expression like `(match () { _ => a }) OP b`, the parens are required - // otherwise the parser would interpret `match () { _ => a }` as a statement, - // with the remaining `OP b` not making sense. So we force parens. - (&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN, _ => left_prec, }; - self.print_expr_maybe_paren(lhs, left_prec, fixup); + self.print_expr_maybe_paren( + lhs, + left_prec, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); + self.space(); self.word_space(op.node.as_str()); - self.print_expr_maybe_paren(rhs, right_prec, fixup) + + self.print_expr_maybe_paren( + rhs, + right_prec, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) { self.word(op.as_str()); - self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup) + self.print_expr_maybe_paren( + expr, + parser::PREC_PREFIX, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } fn print_expr_addr_of( @@ -322,7 +431,11 @@ impl<'a> State<'a> { self.print_mutability(mutability, true); } } - self.print_expr_maybe_paren(expr, parser::PREC_PREFIX, fixup) + self.print_expr_maybe_paren( + expr, + parser::PREC_PREFIX, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } pub(super) fn print_expr(&mut self, expr: &ast::Expr, fixup: FixupContext) { @@ -333,7 +446,7 @@ impl<'a> State<'a> { &mut self, expr: &ast::Expr, is_inline: bool, - fixup: FixupContext, + mut fixup: FixupContext, ) { self.maybe_print_comment(expr.span.lo()); @@ -345,7 +458,27 @@ impl<'a> State<'a> { } self.ibox(INDENT_UNIT); + + // The Match subexpression in `match x {} - 1` must be parenthesized if + // it is the leftmost subexpression in a statement: + // + // (match x {}) - 1; + // + // But not otherwise: + // + // let _ = match x {} - 1; + // + // Same applies to a small set of other expression kinds which eagerly + // terminate a statement which opens with them. + let needs_par = + fixup.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr); + if needs_par { + self.popen(); + fixup = FixupContext::default(); + } + self.ann.pre(self, AnnNode::Expr(expr)); + match &expr.kind { ast::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); @@ -386,7 +519,16 @@ impl<'a> State<'a> { } ast::ExprKind::Cast(expr, ty) => { let prec = AssocOp::As.precedence() as i8; - self.print_expr_maybe_paren(expr, prec, fixup); + self.print_expr_maybe_paren( + expr, + prec, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt + || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); self.space(); self.word_space("as"); self.print_type(ty); @@ -508,31 +650,71 @@ impl<'a> State<'a> { self.print_block_with_attrs(blk, attrs); } ast::ExprKind::Await(expr, _) => { + // Same fixups as ExprKind::MethodCall. self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); self.word(".await"); } ast::ExprKind::Assign(lhs, rhs, _) => { + // Same fixups as ExprKind::Binary. let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(lhs, prec + 1, fixup); + self.print_expr_maybe_paren( + lhs, + prec + 1, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt + || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); self.space(); self.word_space("="); - self.print_expr_maybe_paren(rhs, prec, fixup); + self.print_expr_maybe_paren( + rhs, + prec, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } ast::ExprKind::AssignOp(op, lhs, rhs) => { + // Same fixups as ExprKind::Binary. let prec = AssocOp::Assign.precedence() as i8; - self.print_expr_maybe_paren(lhs, prec + 1, fixup); + self.print_expr_maybe_paren( + lhs, + prec + 1, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt + || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); self.space(); self.word(op.node.as_str()); self.word_space("="); - self.print_expr_maybe_paren(rhs, prec, fixup); + self.print_expr_maybe_paren( + rhs, + prec, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } ast::ExprKind::Field(expr, ident) => { + // Same fixups as ExprKind::MethodCall. self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); self.word("."); self.print_ident(*ident); } ast::ExprKind::Index(expr, index, _) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX, fixup); + // Same fixups as ExprKind::Call. + self.print_expr_maybe_paren( + expr, + parser::PREC_POSTFIX, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt + || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); self.word("["); self.print_expr(index, FixupContext::default()); self.word("]"); @@ -544,14 +726,31 @@ impl<'a> State<'a> { // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) let fake_prec = AssocOp::LOr.precedence() as i8; if let Some(e) = start { - self.print_expr_maybe_paren(e, fake_prec, fixup); + self.print_expr_maybe_paren( + e, + fake_prec, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: fixup.stmt + || fixup.leftmost_subexpression_in_stmt, + ..fixup + }, + ); } match limits { ast::RangeLimits::HalfOpen => self.word(".."), ast::RangeLimits::Closed => self.word("..="), } if let Some(e) = end { - self.print_expr_maybe_paren(e, fake_prec, fixup); + self.print_expr_maybe_paren( + e, + fake_prec, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + ..fixup + }, + ); } } ast::ExprKind::Underscore => self.word("_"), @@ -565,7 +764,15 @@ impl<'a> State<'a> { } if let Some(expr) = opt_expr { self.space(); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup); + self.print_expr_maybe_paren( + expr, + parser::PREC_JUMP, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + ..fixup + }, + ); } } ast::ExprKind::Continue(opt_label) => { @@ -579,7 +786,15 @@ impl<'a> State<'a> { self.word("return"); if let Some(expr) = result { self.word(" "); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup); + self.print_expr_maybe_paren( + expr, + parser::PREC_JUMP, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + ..fixup + }, + ); } } ast::ExprKind::Yeet(result) => { @@ -588,13 +803,25 @@ impl<'a> State<'a> { self.word("yeet"); if let Some(expr) = result { self.word(" "); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup); + self.print_expr_maybe_paren( + expr, + parser::PREC_JUMP, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + ..fixup + }, + ); } } ast::ExprKind::Become(result) => { self.word("become"); self.word(" "); - self.print_expr_maybe_paren(result, parser::PREC_JUMP, fixup); + self.print_expr_maybe_paren( + result, + parser::PREC_JUMP, + FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..fixup }, + ); } ast::ExprKind::InlineAsm(a) => { // FIXME: This should have its own syntax, distinct from a macro invocation. @@ -644,10 +871,19 @@ impl<'a> State<'a> { if let Some(expr) = e { self.space(); - self.print_expr_maybe_paren(expr, parser::PREC_JUMP, fixup); + self.print_expr_maybe_paren( + expr, + parser::PREC_JUMP, + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + ..fixup + }, + ); } } ast::ExprKind::Try(e) => { + // Same fixups as ExprKind::MethodCall. self.print_expr_maybe_paren(e, parser::PREC_POSTFIX, fixup); self.word("?") } @@ -663,7 +899,13 @@ impl<'a> State<'a> { self.pclose() } } + self.ann.post(self, AnnNode::Expr(expr)); + + if needs_par { + self.pclose(); + } + self.end(); } @@ -704,7 +946,7 @@ impl<'a> State<'a> { } _ => { self.end(); // Close the ibox for the pattern. - self.print_expr(body, FixupContext::default()); + self.print_expr(body, FixupContext { stmt: true, ..FixupContext::default() }); self.word(","); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ca65488375c..3ec07572d1d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -482,7 +482,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: Span, use_spans: UseSpans<'tcx>, ) -> DiagnosticBuilder<'cx> { - // We need all statements in the body where the binding was assigned to to later find all + // We need all statements in the body where the binding was assigned to later find all // the branching code paths where the binding *wasn't* assigned to. let inits = &self.move_data.init_path_map[mpi]; let move_path = &self.move_data.move_paths[mpi]; diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2b840860166..b76edd554f8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -420,9 +420,15 @@ pub enum GenericArgsParentheses { /// A modifier on a trait bound. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub enum TraitBoundModifier { + /// `Type: Trait` None, + /// `Type: !Trait` Negative, + /// `Type: ?Trait` Maybe, + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` MaybeConst, } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 139e1c0ac5f..d8b6b9a1272 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -70,7 +70,7 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found hir_analysis_const_bound_for_non_const_trait = - ~const can only be applied to `#[const_trait]` traits + `{$modifier}` can only be applied to `#[const_trait]` traits hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6e71cf16ee8..91b3807d744 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -112,6 +112,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { match ast_bound { hir::GenericBound::Trait(poly_trait_ref, modifier) => { let (constness, polarity) = match modifier { + hir::TraitBoundModifier::Const => { + (ty::BoundConstness::Const, ty::ImplPolarity::Positive) + } hir::TraitBoundModifier::MaybeConst => { (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive) } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 8197fea5b29..092df257dbf 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -560,11 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { inferred_params: vec![], infer_args, }; - if let ty::BoundConstness::ConstIfConst = constness + if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) { - let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span }); + let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + span, + modifier: constness.as_str(), + }); arg_count.correct = Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] }); } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 71fbd983b6a..fd1571426c8 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -32,7 +32,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; } - // If a type in the trait ref is private, then there's also no reason to to do this check. + // If a type in the trait ref is private, then there's also no reason to do this check. let impl_def_id = impl_m.container_id(tcx); for arg in impl_trait_ref.args { if let Some(ty) = arg.as_type() diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 41f30057902..75e7a5524a7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait { pub struct ConstBoundForNonConstTrait { #[primary_span] pub span: Span, + pub modifier: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 6deeb8bee5d..02a35110716 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2080,7 +2080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` /// /// If we're in an irrefutable pattern we prefer the array impl candidate given that - /// the slice impl candidate would be be rejected anyway (if no ambiguity existed). + /// the slice impl candidate would be rejected anyway (if no ambiguity existed). fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool { match decl_origin { Some(DeclOrigin::LocalDecl { els: None }) => true, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9f1ff4538aa..0653796ec7f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -309,23 +309,22 @@ impl Visibility { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub enum BoundConstness { - /// `T: Trait` + /// `Type: Trait` NotConst, - /// `T: ~const Trait` + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` /// /// Requires resolving to const only when we are in a const context. ConstIfConst, } impl BoundConstness { - /// Reduce `self` and `constness` to two possible combined states instead of four. - pub fn and(&mut self, constness: hir::Constness) -> hir::Constness { - match (constness, self) { - (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const, - (_, this) => { - *this = BoundConstness::NotConst; - hir::Constness::NotConst - } + pub fn as_str(self) -> &'static str { + match self { + Self::NotConst => "", + Self::Const => "const", + Self::ConstIfConst => "~const", } } } @@ -334,7 +333,7 @@ impl fmt::Display for BoundConstness { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::NotConst => f.write_str("normal"), - Self::ConstIfConst => f.write_str("`~const`"), + _ => write!(f, "`{self}`"), } } } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index c5a3391286a..078612aa59c 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; -use rustc_span::{ExpnKind, Span, Symbol}; +use rustc_span::{Span, Symbol}; /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen @@ -346,21 +346,10 @@ fn get_body_span<'tcx>( let mut body_span = hir_body.value.span; if tcx.is_closure(def_id.to_def_id()) { - // If the MIR function is a closure, and if the closure body span - // starts from a macro, but it's content is not in that macro, try - // to find a non-macro callsite, and instrument the spans there - // instead. - loop { - let expn_data = body_span.ctxt().outer_expn_data(); - if expn_data.is_root() { - break; - } - if let ExpnKind::Macro { .. } = expn_data.kind { - body_span = expn_data.call_site; - } else { - break; - } - } + // If the current function is a closure, and its "body" span was created + // by macro expansion or compiler desugaring, try to walk backwards to + // the pre-expansion call site or body. + body_span = body_span.source_callsite(); } body_span diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index a9c4ea33d0e..474cb205d13 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -204,10 +204,5 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> { /// etc.). #[inline] fn unexpand_into_body_span(span: Span, body_span: Span) -> Option<Span> { - use rustc_span::source_map::original_sp; - - // FIXME(#118525): Consider switching from `original_sp` to `Span::find_ancestor_inside`, - // which is similar but gives slightly different results in some edge cases. - let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); - body_span.contains(original_span).then_some(original_span) + span.find_ancestor_inside_same_ctxt(body_span) } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 1d788a55ff8..8be96b6ba8f 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -9,7 +9,7 @@ use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants}; /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large /// enough discrepancy between them. /// -/// i.e. If there is are two variants: +/// i.e. If there are two variants: /// ``` /// enum Example { /// Small, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 363b8f4bfb9..c6bddbfacd6 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -95,9 +95,6 @@ parse_compound_assignment_expression_in_let = can't reassign to an uninitialized .suggestion = initialize the variable .help = if you meant to overwrite, remove the `let` binding -parse_const_bounds_missing_tilde = const bounds must start with `~` - .suggestion = add `~` - parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments .suggestion = enclose the `const` expression in braces @@ -555,8 +552,8 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl .suggestion_add_trait = add a trait here .suggestion_remove_for = for an inherent impl, drop this `for` -parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds - .suggestion = remove the `{$sigil}` +parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds + .suggestion = remove the `{$modifier}` parse_more_than_one_char = character literal may only contain one codepoint .followed_by = this `{$chr}` is followed by the combining {$len -> @@ -729,8 +726,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box` parse_ternary_operator = Rust has no ternary operator .help = use an `if-else` expression instead -parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds - parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator .suggestion = use `!` to perform bitwise not diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 53cce9e2883..e276b34ca37 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2556,19 +2556,12 @@ pub(crate) struct AssocLifetime { } #[derive(Diagnostic)] -#[diag(parse_tilde_const_lifetime)] -pub(crate) struct TildeConstLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_modifier_lifetime)] pub(crate) struct ModifierLifetime { #[primary_span] #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")] pub span: Span, - pub sigil: &'static str, + pub modifier: &'static str, } #[derive(Diagnostic)] @@ -2582,15 +2575,6 @@ pub(crate) struct ParenthesizedLifetime { } #[derive(Diagnostic)] -#[diag(parse_const_bounds_missing_tilde)] -pub(crate) struct ConstMissingTilde { - #[primary_span] - pub span: Span, - #[suggestion(code = "~", applicability = "machine-applicable")] - pub start: Span, -} - -#[derive(Diagnostic)] #[diag(parse_underscore_literal_suffix)] pub(crate) struct UnderscoreLiteralSuffix { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 42ab23d6292..4be2c662d03 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -86,6 +86,18 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { t == &token::ModSep || t == &token::Lt || t == &token::BinOp(token::Shl) } +fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { + // `Not`, `Tilde` & `Const` are deliberately not part of this list to + // contain the number of potential regressions esp. in MBE code. + // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`. + // `Not` would regress `dyn!(...)` macro calls in Rust 2015. + t.is_path_start() + || t.is_lifetime() + || t == &TokenKind::Question + || t.is_keyword(kw::For) + || t == &TokenKind::OpenDelim(Delimiter::Parenthesis) +} + impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { @@ -665,7 +677,8 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Dyn) && (self.token.uninterpolated_span().at_least_rust_2018() || self.look_ahead(1, |t| { - (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star)) + (can_begin_dyn_bound_in_edition_2015(t) + || t.kind == TokenKind::BinOp(token::Star)) && !can_continue_type_after_non_fn_ident(t) })) } @@ -758,12 +771,12 @@ impl<'a> Parser<'a> { /// Can the current token begin a bound? fn can_begin_bound(&mut self) -> bool { - // This needs to be synchronized with `TokenKind::can_begin_bound`. self.check_path() || self.check_lifetime() || self.check(&token::Not) || self.check(&token::Question) || self.check(&token::Tilde) + || self.check_keyword(kw::Const) || self.check_keyword(kw::For) || self.check(&token::OpenDelim(Delimiter::Parenthesis)) } @@ -812,8 +825,11 @@ impl<'a> Parser<'a> { fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) { match modifiers.constness { BoundConstness::Never => {} - BoundConstness::Maybe(span) => { - self.dcx().emit_err(errors::TildeConstLifetime { span }); + BoundConstness::Always(span) | BoundConstness::Maybe(span) => { + self.dcx().emit_err(errors::ModifierLifetime { + span, + modifier: modifiers.constness.as_str(), + }); } } @@ -822,7 +838,7 @@ impl<'a> Parser<'a> { BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => { self.dcx().emit_err(errors::ModifierLifetime { span, - sigil: modifiers.polarity.as_str(), + modifier: modifiers.polarity.as_str(), }); } } @@ -848,7 +864,7 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TRAIT_BOUND_MODIFIERS = ["~const"] ["?" | "!"] + /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"] /// ``` fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let constness = if self.eat(&token::Tilde) { @@ -858,11 +874,8 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::const_trait_impl, span); BoundConstness::Maybe(span) } else if self.eat_keyword(kw::Const) { - let span = self.prev_token.span; - self.sess.gated_spans.gate(sym::const_trait_impl, span); - self.dcx().emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() }); - - BoundConstness::Maybe(span) + self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); + BoundConstness::Always(self.prev_token.span) } else { BoundConstness::Never }; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a8ba9838780..6be01e0d88f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -405,7 +405,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { if let Res::Local(_var_hir_id) = path.res { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); } - intravisit::walk_expr(self, expr); } hir::ExprKind::Closure(closure) => { // Interesting control flow (for loops can contain labeled @@ -425,12 +424,10 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { })); } self.set_captures(expr.hir_id, call_caps); - intravisit::walk_expr(self, expr); } hir::ExprKind::Let(let_expr) => { self.add_from_pat(let_expr.pat); - intravisit::walk_expr(self, expr); } // live nodes required for interesting control flow: @@ -439,11 +436,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Loop(..) | hir::ExprKind::Yield(..) => { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); - intravisit::walk_expr(self, expr); } hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id)); - intravisit::walk_expr(self, expr); } // otherwise, live nodes are not required: @@ -474,10 +469,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Type(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) - | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { - intravisit::walk_expr(self, expr); - } + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => {} } + intravisit::walk_expr(self, expr); } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a9c0ab557cb..1923fc15119 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -449,8 +449,8 @@ impl clean::GenericBound { hir::TraitBoundModifier::None => "", hir::TraitBoundModifier::Maybe => "?", hir::TraitBoundModifier::Negative => "!", - // ~const is experimental; do not display those bounds in rustdoc - hir::TraitBoundModifier::MaybeConst => "", + // `const` and `~const` trait bounds are experimental; don't render them. + hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "", }; if f.alternate() { write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx)) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index e824a1fd4bd..e6263db3283 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1805,11 +1805,20 @@ function initSearch(rawSearchIndex) { return unifyFunctionTypes([row], [elem], whereClause, mgens); } - function checkPath(contains, ty, maxEditDistance) { + /** + * Compute an "edit distance" that ignores missing path elements. + * @param {string[]} contains search query path + * @param {Row} ty indexed item + * @returns {null|number} edit distance + */ + function checkPath(contains, ty) { if (contains.length === 0) { return 0; } - let ret_dist = maxEditDistance + 1; + const maxPathEditDistance = Math.floor( + contains.reduce((acc, next) => acc + next.length, 0) / 3 + ); + let ret_dist = maxPathEditDistance + 1; const path = ty.path.split("::"); if (ty.parent && ty.parent.name) { @@ -1821,15 +1830,23 @@ function initSearch(rawSearchIndex) { pathiter: for (let i = length - clength; i >= 0; i -= 1) { let dist_total = 0; for (let x = 0; x < clength; ++x) { - const dist = editDistance(path[i + x], contains[x], maxEditDistance); - if (dist > maxEditDistance) { - continue pathiter; + const [p, c] = [path[i + x], contains[x]]; + if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance && + p.indexOf(c) !== -1 + ) { + // discount distance on substring match + dist_total += Math.floor((p.length - c.length) / 3); + } else { + const dist = editDistance(p, c, maxPathEditDistance); + if (dist > maxPathEditDistance) { + continue pathiter; + } + dist_total += dist; } - dist_total += dist; } ret_dist = Math.min(ret_dist, Math.round(dist_total / clength)); } - return ret_dist; + return ret_dist > maxPathEditDistance ? null : ret_dist; } function typePassesFilter(filter, type) { @@ -2030,8 +2047,8 @@ function initSearch(rawSearchIndex) { } if (elem.fullPath.length > 1) { - path_dist = checkPath(elem.pathWithoutLast, row, maxEditDistance); - if (path_dist > maxEditDistance) { + path_dist = checkPath(elem.pathWithoutLast, row); + if (path_dist === null) { return; } } @@ -2045,7 +2062,7 @@ function initSearch(rawSearchIndex) { const dist = editDistance(row.normalizedName, elem.normalizedPathLast, maxEditDistance); - if (index === -1 && dist + path_dist > maxEditDistance) { + if (index === -1 && dist > maxEditDistance) { return; } @@ -2100,13 +2117,9 @@ function initSearch(rawSearchIndex) { } function innerRunQuery() { - let queryLen = 0; - for (const elem of parsedQuery.elems) { - queryLen += elem.name.length; - } - for (const elem of parsedQuery.returned) { - queryLen += elem.name.length; - } + const queryLen = + parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) + + parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0); const maxEditDistance = Math.floor(queryLen / 3); /** diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 513e94afe29..32d7a80863d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -547,6 +547,9 @@ pub(crate) fn from_trait_bound_modifier( None => TraitBoundModifier::None, Maybe => TraitBoundModifier::Maybe, MaybeConst => TraitBoundModifier::MaybeConst, + // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds + // are less experimental. + Const => TraitBoundModifier::None, // FIXME(negative-bounds): This bound should be rendered negative, but // since that's experimental, maybe let's not add it to the rustdoc json // API just now... diff --git a/tests/rustdoc-js-std/asrawfd.js b/tests/rustdoc-js-std/asrawfd.js index 5b3cfeabbcd..5dbc4ba95d9 100644 --- a/tests/rustdoc-js-std/asrawfd.js +++ b/tests/rustdoc-js-std/asrawfd.js @@ -7,7 +7,6 @@ const EXPECTED = { // Validate that type alias methods get the correct path. { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' }, { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' }, - { 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' }, { 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' }, ], }; diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js new file mode 100644 index 00000000000..822389aaa4f --- /dev/null +++ b/tests/rustdoc-js-std/path-maxeditdistance.js @@ -0,0 +1,42 @@ +// exact-check +const FILTER_CRATE = "std"; +const EXPECTED = [ + { + query: 'vec::intoiterator', + others: [ + // trait std::iter::IntoIterator is not the first result + { 'path': 'std::vec', 'name': 'IntoIter' }, + { 'path': 'std::vec::Vec', 'name': 'into_iter' }, + { 'path': 'std::vec::Drain', 'name': 'into_iter' }, + { 'path': 'std::vec::IntoIter', 'name': 'into_iter' }, + { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, + { 'path': 'std::vec::Splice', 'name': 'into_iter' }, + { 'path': 'std::collections::VecDeque', 'name': 'into_iter' }, + ], + }, + { + query: 'vec::iter', + others: [ + // std::net::ToSocketAttrs::iter should not show up here + { 'path': 'std::vec', 'name': 'IntoIter' }, + { 'path': 'std::vec::Vec', 'name': 'from_iter' }, + { 'path': 'std::vec::Vec', 'name': 'into_iter' }, + { 'path': 'std::vec::Drain', 'name': 'into_iter' }, + { 'path': 'std::vec::IntoIter', 'name': 'into_iter' }, + { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, + { 'path': 'std::vec::Splice', 'name': 'into_iter' }, + { 'path': 'std::collections::VecDeque', 'name': 'iter' }, + { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' }, + { 'path': 'std::collections::VecDeque', 'name': 'from_iter' }, + { 'path': 'std::collections::VecDeque', 'name': 'into_iter' }, + ], + }, + { + query: 'slice::itermut', + others: [ + // std::collections::btree_map::itermut should not show up here + { 'path': 'std::slice', 'name': 'IterMut' }, + { 'path': 'std::slice', 'name': 'iter_mut' }, + ], + }, +]; diff --git a/tests/rustdoc-js-std/path-ordering.js b/tests/rustdoc-js-std/path-ordering.js index c3d61d238cc..e6b7bfab1e5 100644 --- a/tests/rustdoc-js-std/path-ordering.js +++ b/tests/rustdoc-js-std/path-ordering.js @@ -1,11 +1,20 @@ -const EXPECTED = { - query: 'hashset::insert', - others: [ - // ensure hashset::insert comes first - { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' }, - { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' }, - { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' }, - { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' }, - { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' }, - ], -}; +const EXPECTED = [ + { + query: 'hashset::insert', + others: [ + // ensure hashset::insert comes first + { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' }, + ], + }, + { + query: 'hash::insert', + others: [ + // ensure hashset/hashmap::insert come first + { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' }, + { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' }, + ], + }, +]; diff --git a/tests/rustdoc-js/exact-match.js b/tests/rustdoc-js/exact-match.js index ce3a76f9b7d..9e47d27490b 100644 --- a/tests/rustdoc-js/exact-match.js +++ b/tests/rustdoc-js/exact-match.js @@ -3,6 +3,5 @@ const EXPECTED = { 'others': [ { 'path': 'exact_match::Si', 'name': 'pc' }, { 'path': 'exact_match::Psi', 'name': 'pc' }, - { 'path': 'exact_match::Si', 'name': 'pa' }, ], }; diff --git a/tests/rustdoc-js/module-substring.js b/tests/rustdoc-js/module-substring.js index 7a10397ebc6..74c421d7f0b 100644 --- a/tests/rustdoc-js/module-substring.js +++ b/tests/rustdoc-js/module-substring.js @@ -1,7 +1,15 @@ -const EXPECTED = { - 'query': 'ig::pc', - 'others': [ - { 'path': 'module_substring::Sig', 'name': 'pc' }, - { 'path': 'module_substring::Si', 'name': 'pc' }, - ], -}; +const EXPECTED = [ + { + 'query': 'ig::pc', + 'others': [ + { 'path': 'module_substring::Sig', 'name': 'pc' }, + ], + }, + { + 'query': 'si::pc', + 'others': [ + { 'path': 'module_substring::Si', 'name': 'pc' }, + { 'path': 'module_substring::Sig', 'name': 'pc' }, + ], + }, +]; diff --git a/tests/rustdoc-js/path-maxeditdistance.js b/tests/rustdoc-js/path-maxeditdistance.js new file mode 100644 index 00000000000..73b24a6dddf --- /dev/null +++ b/tests/rustdoc-js/path-maxeditdistance.js @@ -0,0 +1,35 @@ +// exact-check + +const EXPECTED = [ + { + 'query': 'xxxxxxxxxxx::hocuspocusprestidigitation', + // do not match abracadabra::hocuspocusprestidigitation + 'others': [], + }, + { + // exact match + 'query': 'abracadabra::hocuspocusprestidigitation', + 'others': [ + { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' }, + ], + }, + { + // swap br/rb; that's edit distance 2, where maxPathEditDistance = 3 (11 / 3) + 'query': 'arbacadarba::hocuspocusprestidigitation', + 'others': [ + { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' }, + ], + }, + { + // truncate 5 chars, where maxEditDistance = 7 (21 / 3) + 'query': 'abracadarba::hocusprestidigitation', + 'others': [ + { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' }, + ], + }, + { + // truncate 9 chars, where maxEditDistance = 5 (17 / 3) + 'query': 'abracadarba::hprestidigitation', + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/path-maxeditdistance.rs b/tests/rustdoc-js/path-maxeditdistance.rs new file mode 100644 index 00000000000..3861280d59b --- /dev/null +++ b/tests/rustdoc-js/path-maxeditdistance.rs @@ -0,0 +1,3 @@ +#![crate_name="abracadabra"] + +pub struct HocusPocusPrestidigitation; diff --git a/tests/rustdoc-js/path-ordering.js b/tests/rustdoc-js/path-ordering.js index f2e6fe2fa61..73d3f4b2755 100644 --- a/tests/rustdoc-js/path-ordering.js +++ b/tests/rustdoc-js/path-ordering.js @@ -1,13 +1,13 @@ // exact-check const EXPECTED = { - 'query': 'b::ccccccc', + 'query': 'bbbbbb::ccccccc', 'others': [ // `ccccccc` is an exact match for all three of these. // However `b` is a closer match for `bb` than for any // of the others, so it ought to go first. - { 'path': 'path_ordering::bb', 'name': 'Ccccccc' }, - { 'path': 'path_ordering::aa', 'name': 'Ccccccc' }, - { 'path': 'path_ordering::dd', 'name': 'Ccccccc' }, + { 'path': 'path_ordering::bbbbbb', 'name': 'Ccccccc' }, + { 'path': 'path_ordering::abbbbb', 'name': 'Ccccccc' }, + { 'path': 'path_ordering::dbbbbb', 'name': 'Ccccccc' }, ], }; diff --git a/tests/rustdoc-js/path-ordering.rs b/tests/rustdoc-js/path-ordering.rs index 7843cf7f9dc..71e24923ed1 100644 --- a/tests/rustdoc-js/path-ordering.rs +++ b/tests/rustdoc-js/path-ordering.rs @@ -1,9 +1,9 @@ -pub mod dd { +pub mod dbbbbb { pub struct Ccccccc; } -pub mod aa { +pub mod abbbbb { pub struct Ccccccc; } -pub mod bb { +pub mod bbbbbb { pub struct Ccccccc; } diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index e5ebe1d8528..e6ea4108f40 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -4,13 +4,13 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls` LL | #![feature(const_fn_trait_ref_impls)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:15:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:15:15 | LL | T: ~const Fn<()> + ~const Destruct, @@ -18,13 +18,13 @@ LL | T: ~const Fn<()> + ~const Destruct, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:22:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:22:15 | LL | T: ~const FnMut<()> + ~const Destruct, @@ -32,13 +32,13 @@ LL | T: ~const FnMut<()> + ~const Destruct, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:29:15 | LL | T: ~const FnOnce<()>, | ^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:29:15 | LL | T: ~const FnOnce<()>, @@ -46,13 +46,13 @@ LL | T: ~const FnOnce<()>, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:36:15 | LL | T: ~const Fn<()> + ~const Destruct, | ^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:36:15 | LL | T: ~const Fn<()> + ~const Destruct, @@ -60,13 +60,13 @@ LL | T: ~const Fn<()> + ~const Destruct, | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:50:15 | LL | T: ~const FnMut<()> + ~const Destruct, | ^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:50:15 | LL | T: ~const FnMut<()> + ~const Destruct, diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index 4b649bf43ed..08147a4afaf 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/unstable-const-fn-in-libcore.rs:19:39 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { diff --git a/tests/ui/generic-const-items/const-trait-impl.rs b/tests/ui/generic-const-items/const-trait-impl.rs index 43cdf818c46..04c3f3eb434 100644 --- a/tests/ui/generic-const-items/const-trait-impl.rs +++ b/tests/ui/generic-const-items/const-trait-impl.rs @@ -1,14 +1,12 @@ -// known-bug: #110395 -// FIXME check-pass +// check-pass // Test that we can call methods from const trait impls inside of generic const items. -#![feature(generic_const_items, const_trait_impl)] +#![feature(generic_const_items, const_trait_impl, effects)] #![allow(incomplete_features)] #![crate_type = "lib"] -// FIXME(generic_const_items, effects): Introduce `const` bounds to make this work. -const CREATE<T: Create>: T = T::create(); +const CREATE<T: const Create>: T = T::create(); pub const K0: i32 = CREATE::<i32>; pub const K1: i32 = CREATE; // arg inferred @@ -23,3 +21,13 @@ impl const Create for i32 { 4096 } } + +trait Mod { // doesn't need to be a `#[const_trait]` + const CREATE<T: const Create>: T; +} + +impl Mod for () { + const CREATE<T: const Create>: T = T::create(); +} + +pub const K2: i32 = <() as Mod>::CREATE::<i32>; diff --git a/tests/ui/generic-const-items/const-trait-impl.stderr b/tests/ui/generic-const-items/const-trait-impl.stderr deleted file mode 100644 index cdcd24eceff..00000000000 --- a/tests/ui/generic-const-items/const-trait-impl.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0015]: cannot call non-const fn `<T as Create>::create` in constants - --> $DIR/const-trait-impl.rs:11:30 - | -LL | const CREATE<T: Create>: T = T::create(); - | ^^^^^^^^^^^ - | - = note: calls in constants are limited to constant functions, tuple structs and tuple variants - = help: add `#![feature(effects)]` to the crate attributes to enable - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index e0513433b8e..7fd2ec57b14 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/normalize-tait-in-const.rs:25:42 | LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 6fc12509aad..192e6e0cc98 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -204,6 +204,16 @@ fn test_expr() { } ], "match self { Ok => 1, Err => 0, }" ); + macro_rules! c2_match_arm { + ([ $expr:expr ], $expr_expected:expr, $tokens_expected:expr $(,)?) => { + c2!(expr, [ match () { _ => $expr } ], $expr_expected, $tokens_expected); + }; + } + c2_match_arm!( + [ { 1 } - 1 ], + "match () { _ => ({ 1 }) - 1, }", + "match() { _ => { 1 } - 1 }", + ); // ExprKind::Closure c1!(expr, [ || {} ], "|| {}"); @@ -651,6 +661,16 @@ fn test_stmt() { "let (a, b): (u32, u32) = (1, 2);", "let(a, b): (u32, u32) = (1, 2)" // FIXME ); + macro_rules! c2_let_expr_minus_one { + ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { + c2!(stmt, [ let _ = $expr - 1 ], $stmt_expected, $tokens_expected); + }; + } + c2_let_expr_minus_one!( + [ match void {} ], + "let _ = match void {} - 1;", + "let _ = match void {} - 1", + ); // StmtKind::Item c1!(stmt, [ struct S; ], "struct S;"); @@ -661,6 +681,46 @@ fn test_stmt() { // StmtKind::Semi c2!(stmt, [ 1 + 1 ], "1 + 1;", "1 + 1"); + macro_rules! c2_expr_as_stmt { + // Parse as expr, then reparse as stmt. + // + // The c2_minus_one macro below can't directly call `c2!(stmt, ...)` + // because `$expr - 1` cannot be parsed directly as a stmt. A statement + // boundary occurs after the `match void {}`, after which the `-` token + // hits "no rules expected this token in macro call". + // + // The unwanted statement boundary is exactly why the pretty-printer is + // injecting parentheses around the subexpression, which is the behavior + // we are interested in testing. + ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { + c2!(stmt, [ $expr ], $stmt_expected, $tokens_expected); + }; + } + macro_rules! c2_minus_one { + ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { + c2_expr_as_stmt!([ $expr - 1 ], $stmt_expected, $tokens_expected); + }; + } + c2_minus_one!( + [ match void {} ], + "(match void {}) - 1;", + "match void {} - 1", + ); + c2_minus_one!( + [ match void {}() ], + "(match void {})() - 1;", + "match void {}() - 1", + ); + c2_minus_one!( + [ match void {}[0] ], + "(match void {})[0] - 1;", + "match void {}[0] - 1", + ); + c2_minus_one!( + [ loop { break 1; } ], + "(loop { break 1; }) - 1;", + "loop { break 1; } - 1", + ); // StmtKind::Empty c1!(stmt, [ ; ], ";"); diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index 4ae4549ea58..bd5f6105f51 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -13,6 +13,7 @@ struct S< T: ~const ?Tr, // OK T: ~const Tr + 'a, // OK T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds + T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds >; fn main() {} diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index 005bc1e54bd..d1210e88d66 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -10,5 +10,11 @@ error: `~const` may only modify trait bounds, not lifetime bounds LL | T: ~const 'a, | ^^^^^^ -error: aborting due to 2 previous errors +error: `const` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:16:8 + | +LL | T: const 'a, + | ^^^^^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs b/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs new file mode 100644 index 00000000000..fe062d62e5a --- /dev/null +++ b/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs @@ -0,0 +1,16 @@ +// Check that `?Trait` matches the macro fragment specifier `ty`. +// Syntactically trait object types can be "bare" (i.e., lack the prefix `dyn`), +// even in newer editions like Rust 2021. +// Therefore the arm `?$Trait:path` shouldn't get reached. + +// edition: 2021 +// check-pass + +macro_rules! check { + ($Ty:ty) => {}; + (?$Trait:path) => { compile_error!("non-ty"); }; +} + +check! { ?Trait } + +fn main() {} diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs index e9b13defe03..240ae3084d6 100644 --- a/tests/ui/parser/trait-object-delimiters.rs +++ b/tests/ui/parser/trait-object-delimiters.rs @@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<` diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr index 51954675093..2ddb734cee0 100644 --- a/tests/ui/parser/trait-object-delimiters.stderr +++ b/tests/ui/parser/trait-object-delimiters.stderr @@ -34,11 +34,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:10:17 | LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {} - | -^ expected one of 10 possible tokens + | -^ expected one of 11 possible tokens | | | help: missing `,` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr index 290ef6e2f5f..58ad1849d4f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -6,7 +6,7 @@ LL | type Bar: ~const std::ops::Add; | = note: this item cannot have `~const` trait bounds -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/assoc-type.rs:17:22 | LL | type Bar: ~const std::ops::Add; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs new file mode 100644 index 00000000000..3582e5e050c --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs @@ -0,0 +1,12 @@ +// Regression test for issue #117244. +#![feature(const_trait_impl, effects)] + +trait NonConst {} + +const fn perform<T: ~const NonConst>() {} +//~^ ERROR `~const` can only be applied to `#[const_trait]` traits + +fn operate<T: const NonConst>() {} +//~^ ERROR `const` can only be applied to `#[const_trait]` traits + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr new file mode 100644 index 00000000000..08954987d31 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr @@ -0,0 +1,14 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/const-bounds-non-const-trait.rs:6:28 + | +LL | const fn perform<T: ~const NonConst>() {} + | ^^^^^^^^ + +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/const-bounds-non-const-trait.rs:9:21 + | +LL | fn operate<T: const NonConst>() {} + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr index fc9b5557a64..ace2e7e46c4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-parse-not-item.rs:7:32 | LL | const fn test() -> impl ~const Fn() { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr index 73ee0f2151a..d70b0d66177 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method-fail.rs:14:39 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr index 33ae7131b92..1642de78692 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method.rs:14:39 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr index 6d61b23e4b7..2e448c64d7a 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr @@ -1,22 +1,22 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:8:19 | LL | F: ~const FnOnce() -> u8, | ^^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:9:19 | LL | F: ~const FnMut() -> u8, | ^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:10:19 | LL | F: ~const Fn() -> u8, | ^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:23:27 | LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr index 13350a6d14a..7529af9293d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr @@ -7,7 +7,7 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop-fail-2.rs:29:26 | LL | const fn check<T: ~const Destruct>(_: T) {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr index 13350a6d14a..7529af9293d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr @@ -7,7 +7,7 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> { = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-drop-fail-2.rs:29:26 | LL | const fn check<T: ~const Destruct>(_: T) {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr index daaba08d7dd..f166bdf6cec 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr @@ -1,10 +1,15 @@ -error: `~const` is not allowed here - --> $DIR/const-drop.rs:67:38 +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:19:32 | -LL | pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>); - | ^^^^^^ +LL | const fn a<T: ~const Destruct>(_: T) {} + | ^ the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:24:13 | - = note: this item cannot have `~const` trait bounds +LL | let _ = S(&mut c); + | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs index 9da84cdb052..4836d2b02ce 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs @@ -4,7 +4,7 @@ #![feature(const_trait_impl)] #![feature(const_mut_refs)] #![feature(never_type)] -// #![cfg_attr(precise, feature(const_precise_live_drops))] +#![cfg_attr(precise, feature(const_precise_live_drops))] use std::marker::Destruct; @@ -63,8 +63,7 @@ mod t { fn foo() {} } - // FIXME(effects): This should be a `const` bound instead of a `~const` one. - pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>); + pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>); impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> { fn drop(&mut self) { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr index daaba08d7dd..23e36887025 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr @@ -1,10 +1,19 @@ -error: `~const` is not allowed here - --> $DIR/const-drop.rs:67:38 +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:19:32 | -LL | pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>); - | ^^^^^^ +LL | const fn a<T: ~const Destruct>(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time + --> $DIR/const-drop.rs:24:13 | - = note: this item cannot have `~const` trait bounds +LL | let _ = S(&mut c); + | ^^^^^^^^^- value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs new file mode 100644 index 00000000000..86706671316 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs @@ -0,0 +1,9 @@ +#![feature(const_trait_impl)] +// edition: 2021 + +#[const_trait] +trait Trait {} + +fn main() { + let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr new file mode 100644 index 00000000000..8b9ba94d099 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr @@ -0,0 +1,8 @@ +error: const trait bounds are not allowed in trait object types + --> $DIR/const-trait-bounds-trait-objects.rs:8:17 + | +LL | let _: &dyn const Trait; + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs new file mode 100644 index 00000000000..1ebebe632c7 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs @@ -0,0 +1,31 @@ +// check-pass + +#![feature(const_trait_impl, effects, generic_const_exprs)] +#![allow(incomplete_features)] + +fn main() { + let _ = process::<()>([()]); + let _ = Struct::<(), 4> { field: [1, 0] }; +} + +fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] { + input +} + +struct Struct<T: const Trait, const P: usize> +where + [u32; T::make(P)]:, +{ + field: [u32; T::make(P)], +} + +#[const_trait] +trait Trait { + fn make(input: usize) -> usize; +} + +impl const Trait for () { + fn make(input: usize) -> usize { + input / 2 + } +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs index 61e31fc9786..c6be75a6a2f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs @@ -1,6 +1,6 @@ #![feature(const_trait_impl, effects)] -const fn test() -> impl ~const Fn() { //~ ERROR ~const can only be applied to `#[const_trait]` traits +const fn test() -> impl ~const Fn() { //~ ERROR `~const` can only be applied to `#[const_trait]` traits const move || { //~ ERROR const closures are experimental let sl: &[u8] = b"foo"; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr index 65808212314..fe6b613d154 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr @@ -7,7 +7,7 @@ LL | const move || { = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information = help: add `#![feature(const_closures)]` to the crate attributes to enable -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-112822-expected-type-for-param.rs:3:32 | LL | const fn test() -> impl ~const Fn() { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr index 663cdd1fe57..12f9355e41d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:14:1 + --> $DIR/feature-gate.rs:22:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs index 0b409fbaac9..015d90aaf21 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs @@ -10,5 +10,13 @@ trait T {} impl const T for S {} //[stock]~^ ERROR const trait impls are experimental +const fn f<A: ~const T>() {} //[stock]~ ERROR const trait impls are experimental +fn g<A: const T>() {} //[stock]~ ERROR const trait impls are experimental + +macro_rules! discard { ($ty:ty) => {} } + +discard! { impl ~const T } //[stock]~ ERROR const trait impls are experimental +discard! { impl const T } //[stock]~ ERROR const trait impls are experimental + #[rustc_error] fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr index 0e938c1c55d..c9826aeb166 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr @@ -7,6 +7,42 @@ LL | impl const T for S {} = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:13:15 + | +LL | const fn f<A: ~const T>() {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:14:9 + | +LL | fn g<A: const T>() {} + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:18:17 + | +LL | discard! { impl ~const T } + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error[E0658]: const trait impls are experimental + --> $DIR/feature-gate.rs:19:17 + | +LL | discard! { impl const T } + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. --> $DIR/feature-gate.rs:8:1 | @@ -16,6 +52,6 @@ LL | #[const_trait] = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs new file mode 100644 index 00000000000..2304a766aaf --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs @@ -0,0 +1,20 @@ +// Ensure that we don't consider `const Trait` and `~const Trait` to +// match the macro fragment specifier `ty` as that would be a breaking +// change theoretically speaking. Syntactically trait object types can +// be "bare", i.e., lack the prefix `dyn`. +// By contrast, `?Trait` *does* match `ty` and therefore an arm like +// `?$Trait:path` would never be reached. +// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`. + +// check-pass + +macro_rules! check { + ($Type:ty) => { compile_error!("ty"); }; + (const $Trait:path) => {}; + (~const $Trait:path) => {}; +} + +check! { const Trait } +check! { ~const Trait } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs new file mode 100644 index 00000000000..9105cb6b043 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs @@ -0,0 +1,20 @@ +// Demonstrates and records a theoretical regressions / breaking changes caused by the +// introduction of const trait bounds. + +// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018. +// edition:2018 + +macro_rules! demo { + ($ty:ty) => { compile_error!("ty"); }; + (impl $c:ident) => {}; + (dyn $c:ident) => {}; +} + +demo! { impl const } +//~^ ERROR expected identifier, found `<eof>` + +demo! { dyn const } +//~^ ERROR const trait impls are experimental +//~| ERROR expected identifier, found `<eof>` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr new file mode 100644 index 00000000000..254d31930b3 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr @@ -0,0 +1,30 @@ +error: expected identifier, found `<eof>` + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14 + | +LL | ($ty:ty) => { compile_error!("ty"); }; + | ------ while parsing argument for this `ty` macro fragment +... +LL | demo! { impl const } + | ^^^^^ expected identifier + +error: expected identifier, found `<eof>` + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13 + | +LL | ($ty:ty) => { compile_error!("ty"); }; + | ------ while parsing argument for this `ty` macro fragment +... +LL | demo! { dyn const } + | ^^^^^ expected identifier + +error[E0658]: const trait impls are experimental + --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13 + | +LL | demo! { dyn const } + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs new file mode 100644 index 00000000000..817e9ee5257 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs @@ -0,0 +1,13 @@ +// Ensure that the introduction of const trait bound didn't regress this code in Rust 2015. +// See also `mbe-const-trait-bound-theoretical-regression.rs`. + +// check-pass + +macro_rules! check { + ($ty:ty) => { compile_error!("ty"); }; + (dyn $c:ident) => {}; +} + +check! { dyn const } + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs new file mode 100644 index 00000000000..37e285f2c65 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs @@ -0,0 +1,20 @@ +#![feature(const_trait_impl)] + +const fn maybe_const_maybe<T: ~const ?Sized>() {} +//~^ ERROR `~const` and `?` are mutually exclusive + +fn const_maybe<T: const ?Sized>() {} +//~^ ERROR `const` and `?` are mutually exclusive + +const fn maybe_const_negative<T: ~const !Trait>() {} +//~^ ERROR `~const` and `!` are mutually exclusive +//~| ERROR negative bounds are not supported + +fn const_negative<T: const !Trait>() {} +//~^ ERROR `const` and `!` are mutually exclusive +//~| ERROR negative bounds are not supported + +#[const_trait] +trait Trait {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr new file mode 100644 index 00000000000..1938f740170 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr @@ -0,0 +1,38 @@ +error: `~const` and `?` are mutually exclusive + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 + | +LL | const fn maybe_const_maybe<T: ~const ?Sized>() {} + | ^^^^^^^^^^^^^ + +error: `const` and `?` are mutually exclusive + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19 + | +LL | fn const_maybe<T: const ?Sized>() {} + | ^^^^^^^^^^^^ + +error: `~const` and `!` are mutually exclusive + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34 + | +LL | const fn maybe_const_negative<T: ~const !Trait>() {} + | ^^^^^^^^^^^^^ + +error: `const` and `!` are mutually exclusive + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22 + | +LL | fn const_negative<T: const !Trait>() {} + | ^^^^^^^^^^^^ + +error: negative bounds are not supported + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 + | +LL | const fn maybe_const_negative<T: ~const !Trait>() {} + | ^ + +error: negative bounds are not supported + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 + | +LL | fn const_negative<T: const !Trait>() {} + | ^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr index b2e09d82a90..ae76cab2f2e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr @@ -1,4 +1,4 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/non-const-op-in-closure-in-const.rs:10:51 | LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr index fd4d7ff3475..eae313ef087 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr @@ -10,13 +10,13 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr index d2e3a5cec1d..be3153d6a08 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr @@ -1,10 +1,10 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} | ^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:10:19 | LL | trait Bar: ~const Foo {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs index 3820d069243..abdf0feee03 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -8,8 +8,8 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: ~const Foo {} -//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` +//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` //[yn,nn]~^^^ ERROR: `~const` is not allowed here const fn foo<T: Bar>(x: &T) { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr index 199d2199c4a..834d6f4dcf3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr @@ -10,13 +10,13 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} @@ -24,7 +24,7 @@ LL | trait Bar: ~const Foo {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:17:24 | LL | const fn foo<T: ~const Bar>(x: &T) { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr index 46eedc333f1..4fdd2284c47 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr @@ -1,10 +1,10 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} | ^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:12:19 | LL | trait Bar: ~const Foo {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs index 3e98e131930..30131d5849c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs @@ -10,12 +10,12 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: ~const Foo {} -//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` +//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` //[yn,nn]~^^^ ERROR: `~const` is not allowed here const fn foo<T: ~const Bar>(x: &T) { - //[yn,nn]~^ ERROR: ~const can only be applied to `#[const_trait]` + //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` x.a(); } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr index dc08a899738..ab7c814eb49 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr @@ -10,7 +10,7 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-3.rs:17:24 | LL | const fn foo<T: ~const Bar>(x: &T) { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs deleted file mode 100644 index ed911d965d6..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(const_trait_impl)] - -const fn tilde_question<T: ~const ?Sized>() {} -//~^ ERROR `~const` and `?` are mutually exclusive - -fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr deleted file mode 100644 index 5850ab41c6b..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `~const` and `?` are mutually exclusive - --> $DIR/tilde-const-maybe-trait.rs:3:28 - | -LL | const fn tilde_question<T: ~const ?Sized>() {} - | ^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs deleted file mode 100644 index d63381b5f2c..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -Z parse-only - -#![feature(const_trait_impl)] - -struct S<T: const Tr>; -//~^ ERROR const bounds must start with `~` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr deleted file mode 100644 index 646cdfc78f9..00000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: const bounds must start with `~` - --> $DIR/without-tilde.rs:5:13 - | -LL | struct S<T: const Tr>; - | -^^^^ - | | - | help: add `~`: `~` - -error: aborting due to 1 previous error - diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index d13cd8f5555..913d51875cd 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,16 +1,16 @@ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:34:16 | LL | impl<T: ~const Default> const A for T { | ^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:40:16 | LL | impl<T: ~const Default + ~const Sup> const A for T { | ^^^^^^^ -error: ~const can only be applied to `#[const_trait]` traits +error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:46:16 | LL | impl<T: ~const Default + ~const Sub> const A for T { |
