diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab2810..a2975935ef553 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -141,16 +141,11 @@ impl Path { /// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_ /// be represented without an anon const in the HIR. /// - /// If `allow_mgca_arg` is true (as should be the case in most situations when - /// `#![feature(min_generic_const_args)]` is enabled), then this always returns true - /// because all paths are valid. - /// - /// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args + /// Returns true iff the path has exactly one segment, and it has no generic args /// (i.e., it is _potentially_ a const parameter). #[tracing::instrument(level = "debug", ret)] - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { - allow_mgca_arg - || self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) + pub fn is_potential_trivial_const_arg(&self) -> bool { + self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) } } @@ -1385,6 +1380,15 @@ pub enum UnsafeSource { UserProvided, } +/// Track whether under `feature(min_generic_const_args)` this anon const +/// was explicitly disambiguated as an anon const or not through the use of +/// `const { ... }` syntax. +#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)] +pub enum MgcaDisambiguation { + AnonConst, + Direct, +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1394,6 +1398,7 @@ pub enum UnsafeSource { pub struct AnonConst { pub id: NodeId, pub value: Box, + pub mgca_disambiguation: MgcaDisambiguation, } /// An expression. @@ -1412,26 +1417,20 @@ impl Expr { /// /// This will unwrap at most one block level (curly braces). After that, if the expression /// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`]. - /// See there for more info about `allow_mgca_arg`. /// - /// The only additional thing to note is that when `allow_mgca_arg` is false, this function - /// will only allow paths with no qself, before dispatching to the `Path` function of - /// the same name. + /// This function will only allow paths with no qself, before dispatching to the `Path` + /// function of the same name. /// /// Does not ensure that the path resolves to a const param/item, the caller should check this. /// This also does not consider macros, so it's only correct after macro-expansion. - pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + pub fn is_potential_trivial_const_arg(&self) -> bool { let this = self.maybe_unwrap_block(); - if allow_mgca_arg { - matches!(this.kind, ExprKind::Path(..)) + if let ExprKind::Path(None, path) = &this.kind + && path.is_potential_trivial_const_arg() + { + true } else { - if let ExprKind::Path(None, path) = &this.kind - && path.is_potential_trivial_const_arg(allow_mgca_arg) - { - true - } else { - false - } + false } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7a0424d395750..49bff8fdd65de 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -415,6 +415,7 @@ macro_rules! common_visitor_and_walkers { UnsafeBinderCastKind, BinOpKind, BlockCheckMode, + MgcaDisambiguation, BorrowKind, BoundAsyncness, BoundConstness, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7230e1c424740..c8a311443a585 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -489,7 +489,11 @@ impl<'hir> LoweringContext<'_, 'hir> { arg }; - let anon_const = AnonConst { id: node_id, value: const_value }; + let anon_const = AnonConst { + id: node_id, + value: const_value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); } else { real_args.push(arg); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c20bbcca44f75..47a8f744820f1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1219,7 +1219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .and_then(|partial_res| partial_res.full_res()) { if !res.matches_ns(Namespace::TypeNS) - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -2287,11 +2287,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> &'hir hir::ConstArg<'hir> { let tcx = self.tcx; - let ct_kind = if path - .is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(res, Res::Def(DefKind::ConstParam, _))) - { + let is_trivial_path = path.is_potential_trivial_const_arg() + && matches!(res, Res::Def(DefKind::ConstParam, _)); + let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() { let qpath = self.lower_qpath( ty_id, &None, @@ -2370,6 +2368,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + #[instrument(level = "debug", skip(self), ret)] + fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> { + let overly_complex_const = |this: &mut Self| { + let e = this.dcx().struct_span_err( + expr.span, + "complex const arguments must be placed inside of a `const` block", + ); + + ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) } + }; + + match &expr.kind { + ExprKind::Path(qself, path) => { + let qpath = self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Explicit, + AllowReturnTypeNotation::No, + // FIXME(mgca): update for `fn foo() -> Bar>` support + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } + } + ExprKind::Underscore => ConstArg { + hir_id: self.lower_node_id(expr.id), + kind: hir::ConstArgKind::Infer(expr.span, ()), + }, + ExprKind::Block(block, _) => { + if let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + && matches!( + expr.kind, + ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..) + ) + { + return self.lower_expr_to_const_arg_direct(expr); + } + + overly_complex_const(self) + } + _ => overly_complex_const(self), + } + } + /// See [`hir::ConstArg`] for when to use this function vs /// [`Self::lower_anon_const_to_anon_const`]. fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { @@ -2379,6 +2424,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "debug", skip(self))] fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { let tcx = self.tcx; + + // We cannot change parsing depending on feature gates available, + // we can only require feature gates to be active as a delayed check. + // Thus we just parse anon consts generally and make the real decision + // making in ast lowering. + // FIXME(min_generic_const_args): revisit once stable + if tcx.features().min_generic_const_args() { + return match anon.mgca_disambiguation { + MgcaDisambiguation::AnonConst => { + let lowered_anon = self.lower_anon_const_to_anon_const(anon); + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) } + } + MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value), + }; + } + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = if let ExprKind::Block(block, _) = &anon.value.kind @@ -2390,12 +2451,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { &anon.value }; + let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); if let ExprKind::Path(qself, path) = &expr.kind - && path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) - && (tcx.features().min_generic_const_args() - || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) + && path.is_potential_trivial_const_arg() + && matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))) { let qpath = self.lower_qpath( expr.id, @@ -2403,7 +2464,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path, ParamMode::Explicit, AllowReturnTypeNotation::No, - // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 88e9bbd710601..dbbd3906b5258 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -517,6 +517,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); + gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index ddc59bfe1414a..9de70b8ced1da 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -17,7 +17,7 @@ mod llvm_enzyme { use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode, FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind, - MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility, + MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility, }; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::{Ident, Span, Symbol, sym}; @@ -558,7 +558,11 @@ mod llvm_enzyme { } GenericParamKind::Const { .. } => { let expr = ecx.expr_path(ast::Path::from_ident(p.ident)); - let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr }; + let anon_const = AnonConst { + id: ast::DUMMY_NODE_ID, + value: expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }; Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const))) } GenericParamKind::Lifetime { .. } => None, @@ -813,6 +817,7 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, 1 + x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; TyKind::Array(ty.clone(), anon_const) }; @@ -827,6 +832,7 @@ mod llvm_enzyme { let anon_const = rustc_ast::AnonConst { id: ast::DUMMY_NODE_ID, value: ecx.expr_usize(span, x.width as usize), + mgca_disambiguation: MgcaDisambiguation::Direct, }; let kind = TyKind::Array(ty.clone(), anon_const); let ty = diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 87a5a440140e0..4126547b0515a 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,5 +1,5 @@ use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -60,8 +60,20 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat { fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat { let kind = match pat.kind { ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( - start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), - end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })), + start.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), + end.map(|value| { + Box::new(AnonConst { + id: DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) + }), include_end, ), ast::PatKind::Or(variants) => { diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 6be65b0fff16f..e5c06889f3e06 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ - self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, - UnOp, attr, token, tokenstream, + self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, + MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, }; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -101,6 +101,7 @@ impl<'a> ExtCtxt<'a> { attrs: AttrVec::new(), tokens: None, }), + mgca_disambiguation: MgcaDisambiguation::Direct, } } diff --git a/compiler/rustc_parse/src/parser/asm.rs b/compiler/rustc_parse/src/parser/asm.rs index 41c3b0f0b676a..caec877232a66 100644 --- a/compiler/rustc_parse/src/parser/asm.rs +++ b/compiler/rustc_parse/src/parser/asm.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, AsmMacro}; +use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation}; use rustc_span::{Span, Symbol, kw}; use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos}; @@ -149,7 +149,7 @@ fn parse_asm_operand<'a>( let block = p.parse_block()?; ast::InlineAsmOperand::Label { block } } else if p.eat_keyword(exp!(Const)) { - let anon_const = p.parse_expr_anon_const()?; + let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; ast::InlineAsmOperand::Const { anon_const } } else if p.eat_keyword(exp!(Sym)) { let expr = p.parse_expr()?; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4f6860fead8d0..d7d343ac16b49 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, - Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, + MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -31,16 +31,15 @@ use crate::errors::{ AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, - DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, - HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, - QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, TernaryOperatorSuggestion, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, WrapType, + DocCommentDoesNotDocumentAnything, DocCommentOnParamType, DoubleColonInBound, + ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, + GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, + InInTypo, IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, SuggAddMissingLetStmt, + SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, TernaryOperatorSuggestion, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, }; use crate::parser::FnContext; use crate::parser::attr::InnerAttrPolicy; @@ -2558,36 +2557,6 @@ impl<'a> Parser<'a> { Ok(false) // Don't continue. } - /// Attempt to parse a generic const argument that has not been enclosed in braces. - /// There are a limited number of expressions that are permitted without being encoded - /// in braces: - /// - Literals. - /// - Single-segment paths (i.e. standalone generic const parameters). - /// All other expressions that can be parsed will emit an error suggesting the expression be - /// wrapped in braces. - pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, Box> { - let start = self.token.span; - let attrs = self.parse_outer_attributes()?; - let (expr, _) = - self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { - err.span_label( - start.shrink_to_lo(), - "while parsing a const generic argument starting here", - ); - err - })?; - if !self.expr_is_valid_const_arg(&expr) { - self.dcx().emit_err(ConstGenericWithoutBraces { - span: expr.span, - sugg: ConstGenericWithoutBracesSugg { - left: expr.span.shrink_to_lo(), - right: expr.span.shrink_to_hi(), - }, - }); - } - Ok(expr) - } - fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option { let snapshot = self.create_snapshot_for_diagnostic(); let param = match self.parse_const_param(AttrVec::new()) { @@ -2623,7 +2592,11 @@ impl<'a> Parser<'a> { self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); let value = self.mk_expr_err(param.span(), guar); - Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) + Some(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })) } pub(super) fn recover_const_param_declaration( @@ -2707,7 +2680,11 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(start.to(expr.span), guar); - return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + return Ok(GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + })); } else if snapshot.token == token::Colon && expr.span.lo() == snapshot.token.span.hi() && matches!(expr.kind, ExprKind::Path(..)) @@ -2776,7 +2753,11 @@ impl<'a> Parser<'a> { ); let guar = err.emit(); let value = self.mk_expr_err(span, guar); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } /// Some special error handling for the "top-level" patterns in a match arm, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fa5e61d24d911..3f0853a3c54df 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::{ self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, - FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, - UnOp, UnsafeBinderCastKind, YieldKind, + FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, + StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; @@ -85,8 +85,15 @@ impl<'a> Parser<'a> { ) } - pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> { - self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) + pub fn parse_expr_anon_const( + &mut self, + mgca_disambiguation: impl FnOnce(&Self, &Expr) -> MgcaDisambiguation, + ) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { + id: DUMMY_NODE_ID, + mgca_disambiguation: mgca_disambiguation(self, &value), + value, + }) } fn parse_expr_catch_underscore( @@ -1615,7 +1622,18 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(exp!(Semi)) { // Repeating array syntax: `[ 0; 512 ]` - let count = self.parse_expr_anon_const()?; + let count = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(exp!(Comma)) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d0..b4ce30767cb8c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1431,7 +1431,7 @@ impl<'a> Parser<'a> { let rhs = if self.eat(exp!(Eq)) { if attr::contains_name(attrs, sym::type_const) { - Some(ConstItemRhs::TypeConst(self.parse_expr_anon_const()?)) + Some(ConstItemRhs::TypeConst(self.parse_const_arg()?)) } else { Some(ConstItemRhs::Body(self.parse_expr()?)) } @@ -1650,8 +1650,11 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) }; - let disr_expr = - if this.eat(exp!(Eq)) { Some(this.parse_expr_anon_const()?) } else { None }; + let disr_expr = if this.eat(exp!(Eq)) { + Some(this.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?) + } else { + None + }; let vr = ast::Variant { ident, @@ -1864,7 +1867,7 @@ impl<'a> Parser<'a> { if p.token == token::Eq { let mut snapshot = p.create_snapshot_for_diagnostic(); snapshot.bump(); - match snapshot.parse_expr_anon_const() { + match snapshot.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst) { Ok(const_expr) => { let sp = ty.span.shrink_to_hi().to(const_expr.value.span); p.psess.gated_spans.gate(sym::default_field_values, sp); @@ -2066,7 +2069,7 @@ impl<'a> Parser<'a> { } let default = if self.token == token::Eq { self.bump(); - let const_expr = self.parse_expr_anon_const()?; + let const_expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); self.psess.gated_spans.gate(sym::default_field_values, sp); Some(const_expr) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8577ea40589a8..c86d586e4783e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -35,9 +35,9 @@ use rustc_ast::tokenstream::{ }; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, - Visibility, VisibilityKind, + self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind, + DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, + Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -727,7 +727,10 @@ impl<'a> Parser<'a> { } fn check_const_arg(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + let is_mcg_arg = self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const); + let is_mgca_arg = self.is_keyword_ahead(0, &[kw::Const]) + && self.look_ahead(1, |t| *t == token::OpenBrace); + is_mcg_arg || is_mgca_arg } fn check_const_closure(&self) -> bool { @@ -1299,6 +1302,20 @@ impl<'a> Parser<'a> { } } + fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> { + self.expect_keyword(exp!(Const))?; + let kw_span = self.token.span; + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + if gate_syntax { + self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span)); + } + Ok(AnonConst { + id: ast::DUMMY_NODE_ID, + value, + mgca_disambiguation: MgcaDisambiguation::AnonConst, + }) + } + /// Parses inline const expressions. fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> { self.expect_keyword(exp!(Const))?; @@ -1306,6 +1323,7 @@ impl<'a> Parser<'a> { let anon_const = AnonConst { id: DUMMY_NODE_ID, value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + mgca_disambiguation: MgcaDisambiguation::AnonConst, }; let blk_span = anon_const.value.span; let kind = if pat { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 437f6da67b74e..ce9e9c73669ee 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -4,8 +4,8 @@ use ast::token::IdentIsRaw; use rustc_ast::token::{self, MetaVarKind, Token, TokenKind}; use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint, - AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs, - Path, PathSegment, QSelf, + AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, MgcaDisambiguation, + ParenthesizedArgs, Path, PathSegment, QSelf, }; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{BytePos, Ident, Span, kw, sym}; @@ -16,12 +16,13 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; use crate::ast::{PatKind, TyKind}; use crate::errors::{ - self, AttributeOnEmptyType, AttributeOnGenericArg, FnPathFoundNamedParams, - PathFoundAttributeInParams, PathFoundCVariadicParams, PathSingleColon, PathTripleColon, + self, AttributeOnEmptyType, AttributeOnGenericArg, ConstGenericWithoutBraces, + ConstGenericWithoutBracesSugg, FnPathFoundNamedParams, PathFoundAttributeInParams, + PathFoundCVariadicParams, PathSingleColon, PathTripleColon, }; use crate::exp; use crate::parser::{ - CommaRecoveryMode, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, + CommaRecoveryMode, Expr, ExprKind, FnContext, FnParseMode, RecoverColon, RecoverComma, }; /// Specifies how to parse a path. @@ -870,12 +871,75 @@ impl<'a> Parser<'a> { /// the caller. pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> { // Parse const argument. - let value = if self.token.kind == token::OpenBrace { - self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)? + let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace { + let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?; + (value, MgcaDisambiguation::Direct) + } else if self.token.is_keyword(kw::Const) { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + let value = self.parse_mgca_const_block(true)?; + (value.value, MgcaDisambiguation::AnonConst) } else { - self.handle_unambiguous_unbraced_const_arg()? + self.parse_unambiguous_unbraced_const_arg()? }; - Ok(AnonConst { id: ast::DUMMY_NODE_ID, value }) + Ok(AnonConst { id: ast::DUMMY_NODE_ID, value, mgca_disambiguation }) + } + + /// Attempt to parse a const argument that has not been enclosed in braces. + /// There are a limited number of expressions that are permitted without being + /// enclosed in braces: + /// - Literals. + /// - Single-segment paths (i.e. standalone generic const parameters). + /// All other expressions that can be parsed will emit an error suggesting the expression be + /// wrapped in braces. + pub(super) fn parse_unambiguous_unbraced_const_arg( + &mut self, + ) -> PResult<'a, (Box, MgcaDisambiguation)> { + let start = self.token.span; + let attrs = self.parse_outer_attributes()?; + let (expr, _) = + self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| { + err.span_label( + start.shrink_to_lo(), + "while parsing a const generic argument starting here", + ); + err + })?; + if !self.expr_is_valid_const_arg(&expr) { + self.dcx().emit_err(ConstGenericWithoutBraces { + span: expr.span, + sugg: ConstGenericWithoutBracesSugg { + left: expr.span.shrink_to_lo(), + right: expr.span.shrink_to_hi(), + }, + }); + } + + let mgca_disambiguation = self.mgca_direct_lit_hack(&expr); + Ok((expr, mgca_disambiguation)) + } + + /// Under `min_generic_const_args` we still allow *some* anon consts to be written without + /// a `const` block as it makes things quite a lot nicer. This function is useful for contexts + /// where we would like to use `MgcaDisambiguation::Direct` but need to fudge it to be `AnonConst` + /// in the presence of literals. + // + /// FIXME(min_generic_const_args): In the long term it would be nice to have a way to directly + /// represent literals in `hir::ConstArgKind` so that we can remove this special case by not + /// needing an anon const. + pub fn mgca_direct_lit_hack(&self, expr: &Expr) -> MgcaDisambiguation { + match &expr.kind { + ast::ExprKind::Lit(_) => MgcaDisambiguation::AnonConst, + ast::ExprKind::Unary(ast::UnOp::Neg, expr) + if matches!(expr.kind, ast::ExprKind::Lit(_)) => + { + MgcaDisambiguation::AnonConst + } + _ => MgcaDisambiguation::Direct, + } } /// Parse a generic argument in a path segment. @@ -976,7 +1040,11 @@ impl<'a> Parser<'a> { GenericArg::Type(_) => GenericArg::Type(self.mk_ty(attr_span, TyKind::Err(guar))), GenericArg::Const(_) => { let error_expr = self.mk_expr(attr_span, ExprKind::Err(guar)); - GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value: error_expr }) + GenericArg::Const(AnonConst { + id: ast::DUMMY_NODE_ID, + value: error_expr, + mgca_disambiguation: MgcaDisambiguation::Direct, + }) } GenericArg::Lifetime(lt) => GenericArg::Lifetime(lt), })); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index c79b99a80e87a..6765143445866 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -2,9 +2,9 @@ use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, - GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, - Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, - TyKind, UnsafeBinderTy, + GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation, + MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, + TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; @@ -658,7 +658,19 @@ impl<'a> Parser<'a> { }; let ty = if self.eat(exp!(Semi)) { - let mut length = self.parse_expr_anon_const()?; + let mut length = if self.token.is_keyword(kw::Const) + && self.look_ahead(1, |t| *t == token::OpenBrace) + { + // While we could just disambiguate `Direct` from `AnonConst` by + // treating all const block exprs as `AnonConst`, that would + // complicate the DefCollector and likely all other visitors. + // So we strip the const blockiness and just store it as a block + // in the AST with the extra disambiguator on the AnonConst + self.parse_mgca_const_block(false)? + } else { + self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))? + }; + if let Err(e) = self.expect(exp!(CloseBracket)) { // Try to recover from `X` when `X::` works self.check_mistyped_turbofish_with_multiple_type_params(e, &mut length.value)?; @@ -699,8 +711,9 @@ impl<'a> Parser<'a> { _ = self.eat(exp!(Comma)) || self.eat(exp!(Colon)) || self.eat(exp!(Star)); let suggestion_span = self.prev_token.span.with_lo(hi); + // FIXME(mgca): recovery is broken for `const {` args // we first try to parse pattern like `[u8 5]` - let length = match self.parse_expr_anon_const() { + let length = match self.parse_expr_anon_const(|_, _| MgcaDisambiguation::Direct) { Ok(length) => length, Err(e) => { e.cancel(); @@ -788,7 +801,7 @@ impl<'a> Parser<'a> { /// an error type. fn parse_typeof_ty(&mut self, lo: Span) -> PResult<'a, TyKind> { self.expect(exp!(OpenParen))?; - let _expr = self.parse_expr_anon_const()?; + let _expr = self.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?; self.expect(exp!(CloseParen))?; let span = lo.to(self.prev_token.span); let guar = self diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f1a03d5a06109..50e11fdde5684 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1222,7 +1222,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - && path.is_potential_trivial_const_arg(false) + && path.is_potential_trivial_const_arg() { let mut check_ns = |ns| { self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) @@ -4840,9 +4840,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { constant, anon_const_kind ); - let is_trivial_const_arg = constant - .value - .is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args()); + let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() { + matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct) + } else { + constant.value.is_potential_trivial_const_arg() + }; + self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { this.resolve_expr(&constant.value, None) }) @@ -5023,9 +5026,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. if const_args.contains(&idx) { - let is_trivial_const_arg = argument.is_potential_trivial_const_arg( - self.r.tcx.features().min_generic_const_args(), - ); + // FIXME(mgca): legacy const generics doesn't support mgca but maybe + // that's okay. + let is_trivial_const_arg = argument.is_potential_trivial_const_arg(); self.resolve_anon_const_manual( is_trivial_const_arg, AnonConstKind::ConstArg(IsRepeatExpr::No), diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs index 2ff5a0353a0a6..27261a4806eb5 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.rs @@ -10,7 +10,7 @@ trait Parent0 { const K: (); } -fn take0(_: impl Trait0) {} +fn take0(_: impl Trait0) {} //~^ ERROR ambiguous associated constant `K` in bounds of `Trait0` trait Trait1: Parent1 + Parent2 {} diff --git a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr index 3541664d1c6a7..9ab39e6b8a608 100644 --- a/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-ambiguity.stderr @@ -7,14 +7,14 @@ LL | const K: (); | ambiguous `K` from `Parent0` | ambiguous `K` from `Parent0` ... -LL | fn take0(_: impl Trait0) {} - | ^^^^^^^^^^ ambiguous associated constant `K` +LL | fn take0(_: impl Trait0) {} + | ^^^^^^^^^^^^^ ambiguous associated constant `K` | = help: consider introducing a new type parameter `T` and adding `where` constraints: where T: Trait0, - T: Parent0::K = { () }, - T: Parent0::K = { () } + T: Parent0::K = { }, + T: Parent0::K = { } error[E0222]: ambiguous associated constant `C` in bounds of `Trait1` --> $DIR/assoc-const-eq-ambiguity.rs:26:25 diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs index 8334e67ae9a12..7f8b3036c3e82 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.rs @@ -18,7 +18,7 @@ trait Trait { fn take( _: impl Trait< < fn(&'a str) -> &'a str as Project>::Out as Discard>::Out, - K = { () } + K = const { () } >, ) {} //~^^^ ERROR higher-ranked subtype error diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr index 9fac60763dae3..4a4c2b285829f 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty-not-wf.stderr @@ -1,14 +1,14 @@ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ error: higher-ranked subtype error - --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13 + --> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:19 | -LL | K = { () } - | ^^^^^^ +LL | K = const { () } + | ^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs index ef8077b9f44a5..d3975bc19ad33 100644 --- a/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-bound-var-in-ty.rs @@ -21,7 +21,7 @@ trait Trait { fn take( _: impl Trait< fn(&'a str) -> &'a str as Discard>::Out, - K = { () } + K = const { } >, ) {} diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs index 1ab93ea596a76..2571af57e66ba 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.rs @@ -8,7 +8,7 @@ trait Trait<'a> { const K: &'a (); } -fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} //~^ ERROR the type of the associated constant `K` cannot capture late-bound generic parameters //~| NOTE its type cannot capture the late-bound lifetime parameter `'r` //~| NOTE the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr index d6a7eb6cfc7d9..44304443ac542 100644 --- a/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-esc-bound-var-in-ty.stderr @@ -1,7 +1,7 @@ error: the type of the associated constant `K` cannot capture late-bound generic parameters --> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:11:35 | -LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {} +LL | fn take(_: impl for<'r> Trait<'r, K = const { &() }>) {} | -- ^ its type cannot capture the late-bound lifetime parameter `'r` | | | the late-bound lifetime parameter `'r` is defined here diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs index 0afb95a0b0336..242ad385947aa 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs @@ -15,31 +15,33 @@ trait Trait<'a, T: 'a + ConstParamTy_, const N: usize> { const K: &'a [T; N]; } -fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} -//~^ ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the lifetime parameter `'r` -//~| NOTE the lifetime parameter `'r` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the type parameter `A` -//~| NOTE the type parameter `A` is defined here -//~| NOTE `K` has type `&'r [A; Q]` -//~| ERROR the type of the associated constant `K` must not depend on generic parameters -//~| NOTE its type must not depend on the const parameter `Q` -//~| NOTE the const parameter `Q` is defined here -//~| NOTE `K` has type `&'r [A; Q]` +fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + //~^ NOTE the lifetime parameter `'r` is defined here + //~| NOTE the type parameter `A` is defined here + //~| NOTE the const parameter `Q` is defined here + _: impl Trait<'r, A, Q, K = const { loop {} }> + //~^ ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the lifetime parameter `'r` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the type parameter `A` + //~| NOTE `K` has type `&'r [A; Q]` + //~| ERROR the type of the associated constant `K` must not depend on generic parameters + //~| NOTE its type must not depend on the const parameter `Q` + //~| NOTE `K` has type `&'r [A; Q]` +) {} trait Project: ConstParamTy_ { #[type_const] const SELF: Self; } -fn take1(_: impl Project) {} +fn take1(_: impl Project) {} //~^ ERROR the type of the associated constant `SELF` must not depend on `impl Trait` //~| NOTE its type must not depend on `impl Trait` //~| NOTE the `impl Trait` is specified here -fn take2>(_: P) {} +fn take2>(_: P) {} //~^ ERROR the type of the associated constant `SELF` must not depend on generic parameters //~| NOTE its type must not depend on the type parameter `P` //~| NOTE the type parameter `P` is defined here @@ -48,7 +50,7 @@ fn take2>(_: P) {} trait Iface<'r>: ConstParamTy_ { //~^ NOTE the lifetime parameter `'r` is defined here //~| NOTE the lifetime parameter `'r` is defined here - type Assoc: Trait<'r, Self, Q, K = { loop {} }> + type Assoc: Trait<'r, Self, Q, K = const { loop {} }> //~^ ERROR the type of the associated constant `K` must not depend on generic parameters //~| ERROR the type of the associated constant `K` must not depend on generic parameters //~| NOTE its type must not depend on the lifetime parameter `'r` diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr index 229dd10c0bebf..b742e68044b0c 100644 --- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr +++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr @@ -1,42 +1,49 @@ error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | -- the lifetime parameter `'r` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A` +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the type parameter `A` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the type parameter `A` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:18:77 + --> $DIR/assoc-const-eq-param-in-ty.rs:22:29 | -LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {} - | - ^ its type must not depend on the const parameter `Q` - | | - | the const parameter `Q` is defined here +LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>( + | - the const parameter `Q` is defined here +... +LL | _: impl Trait<'r, A, Q, K = const { loop {} }> + | ^ its type must not depend on the const parameter `Q` | = note: `K` has type `&'r [A; Q]` error: the type of the associated constant `SELF` must not depend on `impl Trait` - --> $DIR/assoc-const-eq-param-in-ty.rs:37:26 + --> $DIR/assoc-const-eq-param-in-ty.rs:39:26 | -LL | fn take1(_: impl Project) {} - | -------------^^^^------ +LL | fn take1(_: impl Project) {} + | -------------^^^^------------ | | | | | its type must not depend on `impl Trait` | the `impl Trait` is specified here error: the type of the associated constant `SELF` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:42:21 + --> $DIR/assoc-const-eq-param-in-ty.rs:44:21 | -LL | fn take2>(_: P) {} +LL | fn take2>(_: P) {} | - ^^^^ its type must not depend on the type parameter `P` | | | the type parameter `P` is defined here @@ -44,28 +51,28 @@ LL | fn take2>(_: P) {} = note: `SELF` has type `P` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here @@ -73,30 +80,30 @@ LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> = note: `K` has type `&'r [Self; Q]` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | LL | trait Iface<'r>: ConstParamTy_ { | -- the lifetime parameter `'r` is defined here ... -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on the lifetime parameter `'r` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on `Self` - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | ^ its type must not depend on `Self` | = note: `K` has type `&'r [Self; Q]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: the type of the associated constant `K` must not depend on generic parameters - --> $DIR/assoc-const-eq-param-in-ty.rs:51:52 + --> $DIR/assoc-const-eq-param-in-ty.rs:53:52 | -LL | type Assoc: Trait<'r, Self, Q, K = { loop {} }> +LL | type Assoc: Trait<'r, Self, Q, K = const { loop {} }> | - ^ its type must not depend on the const parameter `Q` | | | the const parameter `Q` is defined here diff --git a/tests/ui/associated-consts/assoc-const.rs b/tests/ui/associated-consts/assoc-const.rs index 4eed8bba53b1d..6295fd50b8ffe 100644 --- a/tests/ui/associated-consts/assoc-const.rs +++ b/tests/ui/associated-consts/assoc-const.rs @@ -14,10 +14,10 @@ impl Foo for Bar { const N: usize = 3; } -const TEST:usize = 3; +const TEST: usize = 3; -fn foo>() {} +fn foo>() {} fn main() { foo::() diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs index 0284369f4d658..731ff1564ce26 100644 --- a/tests/ui/associated-consts/issue-110933.rs +++ b/tests/ui/associated-consts/issue-110933.rs @@ -10,7 +10,7 @@ pub trait Trait { pub fn foo< T: Trait< - ASSOC = { + ASSOC = const { let a = 10_usize; let b: &'_ usize = &a; *b diff --git a/tests/ui/associated-type-bounds/const-projection-err.rs b/tests/ui/associated-type-bounds/const-projection-err.rs index 80845ec3ee86e..b230ea77f5fe1 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.rs +++ b/tests/ui/associated-type-bounds/const-projection-err.rs @@ -1,10 +1,6 @@ -//@ revisions: stock gce - #![feature(associated_const_equality, min_generic_const_args)] #![allow(incomplete_features)] -#![cfg_attr(gce, feature(generic_const_exprs))] - trait TraitWAssocConst { #[type_const] const A: usize; diff --git a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr b/tests/ui/associated-type-bounds/const-projection-err.stderr similarity index 66% rename from tests/ui/associated-type-bounds/const-projection-err.gce.stderr rename to tests/ui/associated-type-bounds/const-projection-err.stderr index 9ad851d188d37..552b1579e6183 100644 --- a/tests/ui/associated-type-bounds/const-projection-err.gce.stderr +++ b/tests/ui/associated-type-bounds/const-projection-err.stderr @@ -1,11 +1,13 @@ error[E0271]: type mismatch resolving `::A == 1` - --> $DIR/const-projection-err.rs:16:11 + --> $DIR/const-projection-err.rs:12:11 | LL | foo::(); - | ^ expected `0`, found `1` + | ^ expected `1`, found `0` | + = note: expected constant `1` + found constant `0` note: required by a bound in `foo` - --> $DIR/const-projection-err.rs:13:28 + --> $DIR/const-projection-err.rs:9:28 | LL | fn foo>() {} | ^^^^^ required by this bound in `foo` diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs index 72c1ab559bdf0..7e86148eb811b 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs @@ -81,7 +81,9 @@ fn uncallable(_: impl Iterator) {} fn uncallable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} type MustFail = dyn Iterator; //~^ ERROR [E0719] diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr index a54425c3a2956..6484880392d64 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr +++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr @@ -100,7 +100,7 @@ LL | iter::empty::() | ----------------------- return type was inferred to be `std::iter::Empty` here error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -109,7 +109,7 @@ LL | [2u32].into_iter() | ------------------ return type was inferred to be `std::array::IntoIter` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:86:42 + --> $DIR/duplicate-bound-err.rs:88:42 | LL | type MustFail = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator; | `Item` bound here first error: conflicting associated type bounds for `Item` - --> $DIR/duplicate-bound-err.rs:86:17 + --> $DIR/duplicate-bound-err.rs:88:17 | LL | type MustFail = dyn Iterator; | ^^^^^^^^^^^^^----------^^----------^ @@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator; | `Item` is specified to be `i32` here error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:95:43 + --> $DIR/duplicate-bound-err.rs:97:43 | LL | type MustFail2 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` bound here first error: conflicting associated type bounds for `ASSOC` - --> $DIR/duplicate-bound-err.rs:95:18 + --> $DIR/duplicate-bound-err.rs:97:18 | LL | type MustFail2 = dyn Trait2; | ^^^^^^^^^^^------------^^------------^ @@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2; | `ASSOC` is specified to be `3` here error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified - --> $DIR/duplicate-bound-err.rs:99:43 + --> $DIR/duplicate-bound-err.rs:101:43 | LL | type MustFail3 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here @@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator; | `Item` bound here first error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified - --> $DIR/duplicate-bound-err.rs:102:43 + --> $DIR/duplicate-bound-err.rs:104:43 | LL | type MustFail4 = dyn Trait2; | ------------ ^^^^^^^^^^^^ re-bound here @@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2; | `ASSOC` bound here first error[E0271]: expected `impl Iterator` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:110:17 + --> $DIR/duplicate-bound-err.rs:112:17 | LL | fn foo() -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | note: required by a bound in `Trait3::foo::{anon_assoc#0}` - --> $DIR/duplicate-bound-err.rs:106:31 + --> $DIR/duplicate-bound-err.rs:108:31 | LL | fn foo() -> impl Iterator; | ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}` error[E0271]: expected `Empty` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/duplicate-bound-err.rs:118:16 + --> $DIR/duplicate-bound-err.rs:120:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` @@ -185,7 +185,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: expected `Empty` to be an iterator that yields `u32`, but it yields `i32` - --> $DIR/duplicate-bound-err.rs:119:16 + --> $DIR/duplicate-bound-err.rs:121:16 | LL | uncallable(iter::empty::()); | ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32` @@ -199,7 +199,7 @@ LL | fn uncallable(_: impl Iterator) {} | ^^^^^^^^^^ required by this bound in `uncallable` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:120:22 + --> $DIR/duplicate-bound-err.rs:122:22 | LL | uncallable_const(()); | ---------------- ^^ expected `4`, found `3` @@ -215,7 +215,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:121:22 + --> $DIR/duplicate-bound-err.rs:123:22 | LL | uncallable_const(4u32); | ---------------- ^^^^ expected `3`, found `4` @@ -231,7 +231,7 @@ LL | fn uncallable_const(_: impl Trait) {} | ^^^^^^^^^ required by this bound in `uncallable_const` error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4` - --> $DIR/duplicate-bound-err.rs:122:20 + --> $DIR/duplicate-bound-err.rs:124:20 | LL | uncallable_rtn(()); | -------------- ^^ expected `4`, found `3` @@ -241,13 +241,15 @@ LL | uncallable_rtn(()); = note: expected constant `4` found constant `3` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:75 + --> $DIR/duplicate-bound-err.rs:85:61 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error[E0271]: type mismatch resolving `::ASSOC == 3` - --> $DIR/duplicate-bound-err.rs:123:20 + --> $DIR/duplicate-bound-err.rs:125:20 | LL | uncallable_rtn(17u32); | -------------- ^^^^^ expected `3`, found `4` @@ -257,10 +259,12 @@ LL | uncallable_rtn(17u32); = note: expected constant `3` found constant `4` note: required by a bound in `uncallable_rtn` - --> $DIR/duplicate-bound-err.rs:84:48 + --> $DIR/duplicate-bound-err.rs:85:34 | -LL | fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} - | ^^^^^^^^^ required by this bound in `uncallable_rtn` +LL | fn uncallable_rtn( + | -------------- required by a bound in this function +LL | _: impl Trait, foo(..): Trait> + | ^^^^^^^^^ required by this bound in `uncallable_rtn` error: aborting due to 25 previous errors diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs index 3f40e429260f0..6ea0daeca2c4e 100644 --- a/tests/ui/associated-type-bounds/duplicate-bound.rs +++ b/tests/ui/associated-type-bounds/duplicate-bound.rs @@ -224,7 +224,9 @@ fn uncallable_const(_: impl Trait) {} fn callable_const(_: impl Trait) {} -fn uncallable_rtn(_: impl Trait, foo(..): Trait>) {} +fn uncallable_rtn( + _: impl Trait, foo(..): Trait> +) {} fn callable_rtn(_: impl Trait) {} diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs index edadcd7c80ed2..f28f3f694ff3e 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.rs @@ -12,7 +12,7 @@ impl AssocConst for (T,) { trait Trait {} -impl Trait for () where (U,): AssocConst {} +impl Trait for () where (U,): AssocConst {} //~^ ERROR associated const equality is incomplete //~| ERROR the type parameter `U` is not constrained by the impl trait diff --git a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr index 4106c500215b9..092faff935115 100644 --- a/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr +++ b/tests/ui/const-generics/associated_const_equality/unconstrained_impl_param.stderr @@ -1,8 +1,8 @@ error[E0658]: associated const equality is incomplete --> $DIR/unconstrained_impl_param.rs:15:45 | -LL | impl Trait for () where (U,): AssocConst {} - | ^^^^^^^^^ +LL | impl Trait for () where (U,): AssocConst {} + | ^^^^^ | = note: see issue #92827 for more information = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable @@ -11,7 +11,7 @@ LL | impl Trait for () where (U,): AssocConst {} error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained_impl_param.rs:15:6 | -LL | impl Trait for () where (U,): AssocConst {} +LL | impl Trait for () where (U,): AssocConst {} | ^ unconstrained type parameter error[E0282]: type annotations needed diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs new file mode 100644 index 0000000000000..4592827762660 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -0,0 +1,70 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +type Adt1 = Foo; +type Adt2 = Foo<{ N }>; +type Adt3 = Foo; +//~^ ERROR: generic parameters may not be used in const operations +type Adt4 = Foo<{ 1 + 1 }>; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Adt5 = Foo; + +type Arr = [(); N]; +type Arr2 = [(); { N }]; +type Arr3 = [(); const { N }]; +//~^ ERROR: generic parameters may not be used in const operations +type Arr4 = [(); 1 + 1]; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +type Arr5 = [(); const { 1 + 1 }]; + +fn repeats() { + let _1 = [(); N]; + let _2 = [(); { N }]; + let _3 = [(); const { N }]; + //~^ ERROR: generic parameters may not be used in const operations + let _4 = [(); 1 + 1]; + //~^ ERROR: complex const arguments must be placed inside of a `const` block + let _5 = [(); const { 1 + 1 }]; +} + +#[type_const] +const ITEM1: usize = N; +#[type_const] +const ITEM2: usize = { N }; +#[type_const] +const ITEM3: usize = const { N }; +//~^ ERROR: generic parameters may not be used in const operations +#[type_const] +const ITEM4: usize = { 1 + 1 }; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +#[type_const] +const ITEM5: usize = const { 1 + 1}; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn ace_bounds< + const N: usize, + // We skip the T1 case because it doesn't resolve + // T1: Trait, + T2: Trait, + T3: Trait, + //~^ ERROR: generic parameters may not be used in const operations + T4: Trait, + //~^ ERROR: complex const arguments must be placed inside of a `const` block + T5: Trait, +>() {} + +struct Default1; +struct Default2; +struct Default3; +//~^ ERROR: generic parameters may not be used in const operations +struct Default4; +//~^ ERROR: complex const arguments must be placed inside of a `const` block +struct Default5; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr new file mode 100644 index 0000000000000..e4bf49c71efed --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -0,0 +1,92 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:8:41 + | +LL | type Adt3 = Foo; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:16:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:25:27 + | +LL | let _3 = [(); const { N }]; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:37:46 + | +LL | const ITEM3: usize = const { N }; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:55:31 + | +LL | T3: Trait, + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:64:58 + | +LL | struct Default3; + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments here, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:10:33 + | +LL | type Adt4 = Foo<{ 1 + 1 }>; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:18:34 + | +LL | type Arr4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:27:19 + | +LL | let _4 = [(); 1 + 1]; + | ^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:40:38 + | +LL | const ITEM4: usize = { 1 + 1 }; + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:57:23 + | +LL | T4: Trait, + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts.rs:66:50 + | +LL | struct Default4; + | ^^^^^^^^^ + +error: aborting due to 12 previous errors + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs new file mode 100644 index 0000000000000..979d10331a59b --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -0,0 +1,22 @@ +//@ check-pass + +// We allow for literals to implicitly be anon consts still regardless +// of whether a const block is placed around them or not + +#![feature(min_generic_const_args, associated_const_equality)] +#![expect(incomplete_features)] + +trait Trait { + #[type_const] + const ASSOC: isize; +} + +fn ace>() {} +fn repeat_count() { + [(); 1]; +} +type ArrLen = [(); 1]; +struct Foo; +type NormalArg = (Foo<1>, Foo<-1>); + +fn main() {} diff --git a/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs new file mode 100644 index 0000000000000..31f54abf31ef2 --- /dev/null +++ b/tests/ui/const-generics/mgca/multi_braced_direct_const_args.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +struct Foo; + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +type Arr = [(); {{{ N }}}]; +type Arr2 = [(); {{{ ::ASSOC }}}]; +type Ty = Foo<{{{ N }}}>; +type Ty2 = Foo<{{{ ::ASSOC }}}>; +struct Default; +struct Default2::ASSOC }}}>(T); + +fn repeat() { + let _1 = [(); {{{ N }}}]; + let _2 = [(); {{{ ::ASSOC }}}]; +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs index 27b446e6a40d2..11db82187b847 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.rs +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.rs @@ -4,9 +4,9 @@ struct S; // FIXME(mgca): need support for ctors without anon const -// (we use double-braces to trigger an anon const here) +// (we use a const-block to trigger an anon const here) #[type_const] -const FREE: S = { { S } }; +const FREE: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter trait Tr { @@ -17,9 +17,9 @@ trait Tr { impl Tr for S { // FIXME(mgca): need support for ctors without anon const - // (we use double-braces to trigger an anon const here) + // (we use a const-block to trigger an anon const here) #[type_const] - const N: S = { { S } }; + const N: S = const { S }; //~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter } diff --git a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr index 6b13917a95cd1..d07bbde1e62e7 100644 --- a/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr +++ b/tests/ui/const-generics/mgca/type_const-not-constparamty.stderr @@ -1,7 +1,7 @@ error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:9:13 | -LL | const FREE: S = { { S } }; +LL | const FREE: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct @@ -13,7 +13,7 @@ LL | struct S; error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/type_const-not-constparamty.rs:22:14 | -LL | const N: S = { { S } }; +LL | const N: S = const { S }; | ^ | help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index d38d5ab7a59f8..577fee084dbd5 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -2,10 +2,10 @@ #![feature(min_generic_const_args, generic_const_items)] #[type_const] -const FREE1: usize = std::mem::size_of::(); +const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] -const FREE2: usize = I + 1; +const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations pub trait Tr { @@ -21,13 +21,13 @@ pub struct S; impl Tr for S { #[type_const] - const N1: usize = std::mem::size_of::(); + const N1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N2: usize = I + 1; + const N2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations #[type_const] - const N3: usize = 2 & X; + const N3: usize = const { 2 & X }; //~^ ERROR generic parameters may not be used in const operations } diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 76638f27e96cf..8cef77e5b2294 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -1,44 +1,44 @@ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:5:45 + --> $DIR/type_const-on-generic-expr.rs:5:53 | -LL | const FREE1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const FREE1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:8:38 + --> $DIR/type_const-on-generic-expr.rs:8:46 | -LL | const FREE2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const FREE2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:24:46 + --> $DIR/type_const-on-generic-expr.rs:24:54 | -LL | const N1: usize = std::mem::size_of::(); - | ^ cannot perform const operation using `T` +LL | const N1: usize = const { std::mem::size_of::() }; + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:27:39 + --> $DIR/type_const-on-generic-expr.rs:27:47 | -LL | const N2: usize = I + 1; - | ^ cannot perform const operation using `I` +LL | const N2: usize = const { I + 1 }; + | ^ cannot perform const operation using `I` | = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:30:27 + --> $DIR/type_const-on-generic-expr.rs:30:35 | -LL | const N3: usize = 2 & X; - | ^ cannot perform const operation using `X` +LL | const N3: usize = const { 2 & X }; + | ^ cannot perform const operation using `X` | = help: const parameters may only be used as standalone arguments here, i.e. `X` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs new file mode 100644 index 0000000000000..588fa2f913b63 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.rs @@ -0,0 +1,42 @@ +#![feature(adt_const_params)] + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct Inner; + +struct Foo< + const PARAM_TY: Inner, + //~^ ERROR: unbraced const blocks as const args are experimental + const DEFAULT: usize = const { 1 }, + //~^ ERROR: unbraced const blocks as const args are experimental +>; + +type Array = [(); const { 1 }]; +type NormalTy = Inner; + //~^ ERROR: unbraced const blocks as const args are experimental + +fn repeat() { + [1_u8; const { 1 }]; +} + +fn body_ty() { + let _: Inner; + //~^ ERROR: unbraced const blocks as const args are experimental +} + +fn generic() { + if false { + generic::(); + //~^ ERROR: unbraced const blocks as const args are experimental + } +} + +const NON_TYPE_CONST: usize = const { 1 }; + +#[type_const] +//~^ ERROR: the `#[type_const]` attribute is an experimental feature +const TYPE_CONST: usize = const { 1 }; +//~^ ERROR: unbraced const blocks as const args are experimental + +static STATIC: usize = const { 1 }; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr new file mode 100644 index 0000000000000..30509ddf9b467 --- /dev/null +++ b/tests/ui/const-generics/mgca/unbraced_const_block_const_arg_gated.stderr @@ -0,0 +1,73 @@ +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:7:33 + | +LL | const PARAM_TY: Inner, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:9:34 + | +LL | const DEFAULT: usize = const { 1 }, + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:14:29 + | +LL | type NormalTy = Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:22:24 + | +LL | let _: Inner; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:28:25 + | +LL | generic::(); + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: unbraced const blocks as const args are experimental + --> $DIR/unbraced_const_block_const_arg_gated.rs:37:33 + | +LL | const TYPE_CONST: usize = const { 1 }; + | ^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[type_const]` attribute is an experimental feature + --> $DIR/unbraced_const_block_const_arg_gated.rs:35:1 + | +LL | #[type_const] + | ^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs index 554e078ccd49c..d97b3a9f09294 100644 --- a/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs +++ b/tests/ui/const-generics/mgca/using-fnptr-as-type_const.rs @@ -9,6 +9,6 @@ trait Trait { //~^ ERROR using function pointers as const generic parameters is forbidden } -fn take(_: impl Trait) {} +fn take(_: impl Trait) {} fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs index 7f4926fa2b71f..a72aaedb980e0 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -9,12 +9,12 @@ impl Pins for NoPin {} pub trait PinA { #[type_const] - const A: &'static () = &(); + const A: &'static () = const { &() }; } pub trait Pins {} -impl Pins for T where T: PinA {} +impl Pins for T where T: PinA {} //~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin` pub fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr index 34546349592f5..f57fd74ad99df 100644 --- a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -4,8 +4,8 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` LL | impl Pins for NoPin {} | --------------------------- first implementation here ... -LL | impl Pins for T where T: PinA {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` +LL | impl Pins for T where T: PinA {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` | = note: downstream crates may implement trait `PinA<_>` for type `NoPin` diff --git a/tests/ui/generic-const-items/associated-const-equality.rs b/tests/ui/generic-const-items/associated-const-equality.rs index 6f5d4985ae539..37cf381e68244 100644 --- a/tests/ui/generic-const-items/associated-const-equality.rs +++ b/tests/ui/generic-const-items/associated-const-equality.rs @@ -17,7 +17,7 @@ impl Owner for () { #[type_const] const C: u32 = N; #[type_const] - const K: u32 = 99 + 1; + const K: u32 = const { 99 + 1 }; // FIXME(mgca): re-enable once we properly support ctors and generics on paths // #[type_const] // const Q: Maybe = Maybe::Nothing;