Syntactically distinguish anon const const args

This commit is contained in:
Boxy Uwu 2025-11-19 20:01:24 +00:00
parent 2a3a62d26e
commit acc3a0e2da
48 changed files with 779 additions and 252 deletions

View file

@ -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<Expr>,
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
}
}

View file

@ -415,6 +415,7 @@ macro_rules! common_visitor_and_walkers {
UnsafeBinderCastKind,
BinOpKind,
BlockCheckMode,
MgcaDisambiguation,
BorrowKind,
BoundAsyncness,
BoundConstness,

View file

@ -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);

View file

@ -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<FOO<impl Trait>>` 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<FOO<impl Trait>>` support
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

View file

@ -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");

View file

@ -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 =

View file

@ -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) => {

View file

@ -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,
}
}

View file

@ -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()?;

View file

@ -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<Expr>> {
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<GenericArg> {
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,

View file

@ -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)) {

View file

@ -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)

View file

@ -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<Expr>> {
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 {

View file

@ -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<Expr>, 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),
}));

View file

@ -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<Y, ...>` when `X::<Y, ...>` 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

View file

@ -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),

View file

@ -10,7 +10,7 @@ trait Parent0<T> {
const K: ();
}
fn take0(_: impl Trait0<K = { () }>) {}
fn take0(_: impl Trait0<K = const { }>) {}
//~^ ERROR ambiguous associated constant `K` in bounds of `Trait0`
trait Trait1: Parent1 + Parent2 {}

View file

@ -7,14 +7,14 @@ LL | const K: ();
| ambiguous `K` from `Parent0<u32>`
| ambiguous `K` from `Parent0<i32>`
...
LL | fn take0(_: impl Trait0<K = { () }>) {}
| ^^^^^^^^^^ ambiguous associated constant `K`
LL | fn take0(_: impl Trait0<K = const { }>) {}
| ^^^^^^^^^^^^^ ambiguous associated constant `K`
|
= help: consider introducing a new type parameter `T` and adding `where` constraints:
where
T: Trait0,
T: Parent0<u32>::K = { () },
T: Parent0<i32>::K = { () }
T: Parent0<u32>::K = { },
T: Parent0<i32>::K = { }
error[E0222]: ambiguous associated constant `C` in bounds of `Trait1`
--> $DIR/assoc-const-eq-ambiguity.rs:26:25

View file

@ -18,7 +18,7 @@ trait Trait<T: ConstParamTy_> {
fn take(
_: impl Trait<
<<for<'a> fn(&'a str) -> &'a str as Project>::Out as Discard>::Out,
K = { () }
K = const { () }
>,
) {}
//~^^^ ERROR higher-ranked subtype error

View file

@ -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`

View file

@ -21,7 +21,7 @@ trait Trait<T: ConstParamTy_> {
fn take(
_: impl Trait<
<for<'a> fn(&'a str) -> &'a str as Discard>::Out,
K = { () }
K = const { }
>,
) {}

View file

@ -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

View file

@ -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

View file

@ -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<SELF = {}>) {}
fn take1(_: impl Project<SELF = const {}>) {}
//~^ 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: Project<SELF = {}>>(_: P) {}
fn take2<P: Project<SELF = const {}>>(_: 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: Project<SELF = {}>>(_: P) {}
trait Iface<'r>: ConstParamTy_ {
//~^ NOTE the lifetime parameter `'r` is defined here
//~| NOTE the lifetime parameter `'r` is defined here
type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
type Assoc<const Q: usize>: 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`

View file

@ -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<SELF = {}>) {}
| -------------^^^^------
LL | fn take1(_: impl Project<SELF = const {}>) {}
| -------------^^^^------------
| | |
| | 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: Project<SELF = {}>>(_: P) {}
LL | fn take2<P: Project<SELF = const {}>>(_: 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: Project<SELF = {}>>(_: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: 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<const Q: usize>: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: 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<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = const { loop {} }>
| - ^ its type must not depend on the const parameter `Q`
| |
| the const parameter `Q` is defined here

View file

@ -14,10 +14,10 @@ impl Foo for Bar {
const N: usize = 3;
}
const TEST:usize = 3;
const TEST: usize = 3;
fn foo<F: Foo<N=3usize>>() {}
fn foo<F: Foo<N = 3usize>>() {}
fn main() {
foo::<Bar>()

View file

@ -10,7 +10,7 @@ pub trait Trait {
pub fn foo<
T: Trait<
ASSOC = {
ASSOC = const {
let a = 10_usize;
let b: &'_ usize = &a;
*b

View file

@ -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;

View file

@ -1,11 +1,13 @@
error[E0271]: type mismatch resolving `<T as TraitWAssocConst>::A == 1`
--> $DIR/const-projection-err.rs:16:11
--> $DIR/const-projection-err.rs:12:11
|
LL | foo::<T>();
| ^ 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<T: TraitWAssocConst<A = 1>>() {}
| ^^^^^ required by this bound in `foo`

View file

@ -81,7 +81,9 @@ fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
fn uncallable_rtn(
_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
) {}
type MustFail = dyn Iterator<Item = i32, Item = u32>;
//~^ ERROR [E0719]

View file

@ -100,7 +100,7 @@ LL | iter::empty::<String>()
| ----------------------- return type was inferred to be `std::iter::Empty<String>` here
error[E0271]: expected `IntoIter<u32, 1>` 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<Item = i32, Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -109,7 +109,7 @@ LL | [2u32].into_iter()
| ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` 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<Item = i32, Item = u32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -117,7 +117,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| `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<Item = i32, Item = u32>;
| ^^^^^^^^^^^^^----------^^----------^
@ -126,7 +126,7 @@ LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
| `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<ASSOC = 3u32, ASSOC = 4u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -134,7 +134,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| `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<ASSOC = 3u32, ASSOC = 4u32>;
| ^^^^^^^^^^^------------^^------------^
@ -143,7 +143,7 @@ LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
| `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<Item = i32, Item = i32>;
| ---------- ^^^^^^^^^^ re-bound here
@ -151,7 +151,7 @@ LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
| `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<ASSOC = 3u32, ASSOC = 3u32>;
| ------------ ^^^^^^^^^^^^ re-bound here
@ -159,19 +159,19 @@ LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
| `ASSOC` bound here first
error[E0271]: expected `impl Iterator<Item = u32>` 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<Item = i32, Item = u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<Item = i32, Item = u32>;
| ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
error[E0271]: expected `Empty<u32>` 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::<u32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
@ -185,7 +185,7 @@ LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
| ^^^^^^^^^^ required by this bound in `uncallable`
error[E0271]: expected `Empty<i32>` 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::<i32>());
| ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
@ -199,7 +199,7 @@ LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
| ^^^^^^^^^^ 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<ASSOC = 3, ASSOC = 4>) {}
| ^^^^^^^^^ required by this bound in `uncallable_const`
error[E0271]: type mismatch resolving `<u32 as Trait>::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<ASSOC = 3, ASSOC = 4>) {}
| ^^^^^^^^^ 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<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
LL | fn uncallable_rtn(
| -------------- required by a bound in this function
LL | _: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
error[E0271]: type mismatch resolving `<u32 as Trait>::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<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
LL | fn uncallable_rtn(
| -------------- required by a bound in this function
LL | _: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
| ^^^^^^^^^ required by this bound in `uncallable_rtn`
error: aborting due to 25 previous errors

View file

@ -224,7 +224,9 @@ fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
fn callable_const(_: impl Trait<ASSOC = 3, ASSOC = 3>) {}
fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
fn uncallable_rtn(
_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>
) {}
fn callable_rtn(_: impl Trait<foo(..): Send, foo(..): Send, foo(..): Eq>) {}

View file

@ -12,7 +12,7 @@ impl<T> AssocConst for (T,) {
trait Trait {}
impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
impl<U> Trait for () where (U,): AssocConst<A = 0> {}
//~^ ERROR associated const equality is incomplete
//~| ERROR the type parameter `U` is not constrained by the impl trait

View file

@ -1,8 +1,8 @@
error[E0658]: associated const equality is incomplete
--> $DIR/unconstrained_impl_param.rs:15:45
|
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
| ^^^^^^^^^
LL | impl<U> Trait for () where (U,): AssocConst<A = 0> {}
| ^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
@ -11,7 +11,7 @@ LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
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<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
LL | impl<U> Trait for () where (U,): AssocConst<A = 0> {}
| ^ unconstrained type parameter
error[E0282]: type annotations needed

View file

@ -0,0 +1,70 @@
#![feature(associated_const_equality, generic_const_items, min_generic_const_args)]
#![expect(incomplete_features)]
struct Foo<const N: usize>;
type Adt1<const N: usize> = Foo<N>;
type Adt2<const N: usize> = Foo<{ N }>;
type Adt3<const N: usize> = Foo<const { N }>;
//~^ ERROR: generic parameters may not be used in const operations
type Adt4<const N: usize> = Foo<{ 1 + 1 }>;
//~^ ERROR: complex const arguments must be placed inside of a `const` block
type Adt5<const N: usize> = Foo<const { 1 + 1 }>;
type Arr<const N: usize> = [(); N];
type Arr2<const N: usize> = [(); { N }];
type Arr3<const N: usize> = [(); const { N }];
//~^ ERROR: generic parameters may not be used in const operations
type Arr4<const N: usize> = [(); 1 + 1];
//~^ ERROR: complex const arguments must be placed inside of a `const` block
type Arr5<const N: usize> = [(); const { 1 + 1 }];
fn repeats<const N: usize>() {
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<const N: usize>: usize = N;
#[type_const]
const ITEM2<const N: usize>: usize = { N };
#[type_const]
const ITEM3<const N: usize>: usize = const { N };
//~^ ERROR: generic parameters may not be used in const operations
#[type_const]
const ITEM4<const N: usize>: usize = { 1 + 1 };
//~^ ERROR: complex const arguments must be placed inside of a `const` block
#[type_const]
const ITEM5<const N: usize>: 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<ASSOC = N>,
T2: Trait<ASSOC = { N }>,
T3: Trait<ASSOC = const { N }>,
//~^ ERROR: generic parameters may not be used in const operations
T4: Trait<ASSOC = { 1 + 1 }>,
//~^ ERROR: complex const arguments must be placed inside of a `const` block
T5: Trait<ASSOC = const { 1 + 1 }>,
>() {}
struct Default1<const N: usize, const M: usize = N>;
struct Default2<const N: usize, const M: usize = { N }>;
struct Default3<const N: usize, const M: usize = const { N }>;
//~^ ERROR: generic parameters may not be used in const operations
struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
//~^ ERROR: complex const arguments must be placed inside of a `const` block
struct Default5<const N: usize, const M: usize = const { 1 + 1}>;
fn main() {}

View file

@ -0,0 +1,92 @@
error: generic parameters may not be used in const operations
--> $DIR/explicit_anon_consts.rs:8:41
|
LL | type Adt3<const N: usize> = Foo<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:16:42
|
LL | type Arr3<const N: 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: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<const N: usize>: 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<ASSOC = 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:64:58
|
LL | struct Default3<const N: usize, const M: 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: complex const arguments must be placed inside of a `const` block
--> $DIR/explicit_anon_consts.rs:10:33
|
LL | type Adt4<const N: usize> = 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<const N: usize> = [(); 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<const N: usize>: 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<ASSOC = { 1 + 1 }>,
| ^^^^^^^^^
error: complex const arguments must be placed inside of a `const` block
--> $DIR/explicit_anon_consts.rs:66:50
|
LL | struct Default4<const N: usize, const M: usize = { 1 + 1 }>;
| ^^^^^^^^^
error: aborting due to 12 previous errors

View file

@ -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<T: Trait<ASSOC = 1, ASSOC = -1>>() {}
fn repeat_count() {
[(); 1];
}
type ArrLen = [(); 1];
struct Foo<const N: isize>;
type NormalArg = (Foo<1>, Foo<-1>);
fn main() {}

View file

@ -0,0 +1,25 @@
//@ check-pass
#![feature(min_generic_const_args)]
#![expect(incomplete_features)]
struct Foo<const N: usize>;
trait Trait {
#[type_const]
const ASSOC: usize;
}
type Arr<const N: usize> = [(); {{{ N }}}];
type Arr2<T> = [(); {{{ <T as Trait>::ASSOC }}}];
type Ty<const N: usize> = Foo<{{{ N }}}>;
type Ty2<T> = Foo<{{{ <T as Trait>::ASSOC }}}>;
struct Default<const N: usize, const M: usize = {{{ N }}}>;
struct Default2<T: Trait, const M: usize = {{{ <T as Trait>::ASSOC }}}>(T);
fn repeat<T: Trait, const N: usize>() {
let _1 = [(); {{{ N }}}];
let _2 = [(); {{{ <T as Trait>::ASSOC }}}];
}
fn main() {}

View file

@ -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
}

View file

@ -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

View file

@ -2,10 +2,10 @@
#![feature(min_generic_const_args, generic_const_items)]
#[type_const]
const FREE1<T>: usize = std::mem::size_of::<T>();
const FREE1<T>: usize = const { std::mem::size_of::<T>() };
//~^ ERROR generic parameters may not be used in const operations
#[type_const]
const FREE2<const I: usize>: usize = I + 1;
const FREE2<const I: usize>: usize = const { I + 1 };
//~^ ERROR generic parameters may not be used in const operations
pub trait Tr<const X: usize> {
@ -21,13 +21,13 @@ pub struct S;
impl<const X: usize> Tr<X> for S {
#[type_const]
const N1<T>: usize = std::mem::size_of::<T>();
const N1<T>: usize = const { std::mem::size_of::<T>() };
//~^ ERROR generic parameters may not be used in const operations
#[type_const]
const N2<const I: usize>: usize = I + 1;
const N2<const I: usize>: 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
}

View file

@ -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<T>: usize = std::mem::size_of::<T>();
| ^ cannot perform const operation using `T`
LL | const FREE1<T>: usize = const { std::mem::size_of::<T>() };
| ^ 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<const I: usize>: usize = I + 1;
| ^ cannot perform const operation using `I`
LL | const FREE2<const I: usize>: 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<T>: usize = std::mem::size_of::<T>();
| ^ cannot perform const operation using `T`
LL | const N1<T>: usize = const { std::mem::size_of::<T>() };
| ^ 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<const I: usize>: usize = I + 1;
| ^ cannot perform const operation using `I`
LL | const N2<const I: usize>: 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

View file

@ -0,0 +1,42 @@
#![feature(adt_const_params)]
#[derive(Eq, PartialEq, std::marker::ConstParamTy)]
struct Inner<const N: usize>;
struct Foo<
const PARAM_TY: Inner<const { 1 }>,
//~^ 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<const { 1 }>;
//~^ ERROR: unbraced const blocks as const args are experimental
fn repeat() {
[1_u8; const { 1 }];
}
fn body_ty() {
let _: Inner<const { 1 }>;
//~^ ERROR: unbraced const blocks as const args are experimental
}
fn generic<const N: usize>() {
if false {
generic::<const { 1 }>();
//~^ 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() {}

View file

@ -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<const { 1 }>,
| ^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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<const { 1 }>;
| ^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/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<const { 1 }>;
| ^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/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::<const { 1 }>();
| ^^^^^
|
= note: see issue #132980 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.

View file

@ -9,6 +9,6 @@ trait Trait {
//~^ ERROR using function pointers as const generic parameters is forbidden
}
fn take(_: impl Trait<F = { || {} }>) {}
fn take(_: impl Trait<F = const { || {} }>) {}
fn main() {}

View file

@ -9,12 +9,12 @@ impl<TA> Pins<TA> for NoPin {}
pub trait PinA<PER> {
#[type_const]
const A: &'static () = &();
const A: &'static () = const { &() };
}
pub trait Pins<USART> {}
impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
impl<USART, T> Pins<USART> for T where T: PinA<USART, A = const { &() }> {}
//~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin`
pub fn main() {}

View file

@ -4,8 +4,8 @@ error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin`
LL | impl<TA> Pins<TA> for NoPin {}
| --------------------------- first implementation here
...
LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin`
LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = const { &() }> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin`
|
= note: downstream crates may implement trait `PinA<_>` for type `NoPin`

View file

@ -17,7 +17,7 @@ impl Owner for () {
#[type_const]
const C<const N: u32>: u32 = N;
#[type_const]
const K<const N: u32>: u32 = 99 + 1;
const K<const N: u32>: u32 = const { 99 + 1 };
// FIXME(mgca): re-enable once we properly support ctors and generics on paths
// #[type_const]
// const Q<T>: Maybe<T> = Maybe::Nothing;