Skip to content

Commit 0c86a41

Browse files
committed
Syntactically distinguish anon const const args
1 parent 2e667b0 commit 0c86a41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+780
-253
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,11 @@ impl Path {
141141
/// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_
142142
/// be represented without an anon const in the HIR.
143143
///
144-
/// If `allow_mgca_arg` is true (as should be the case in most situations when
145-
/// `#![feature(min_generic_const_args)]` is enabled), then this always returns true
146-
/// because all paths are valid.
147-
///
148-
/// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args
144+
/// Returns true iff the path has exactly one segment, and it has no generic args
149145
/// (i.e., it is _potentially_ a const parameter).
150146
#[tracing::instrument(level = "debug", ret)]
151-
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
152-
allow_mgca_arg
153-
|| self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
147+
pub fn is_potential_trivial_const_arg(&self) -> bool {
148+
self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none())
154149
}
155150
}
156151

@@ -1385,6 +1380,15 @@ pub enum UnsafeSource {
13851380
UserProvided,
13861381
}
13871382

1383+
/// Track whether under `feature(min_generic_const_args)` this anon const
1384+
/// was explicitly disambiguated as an anon const or not through the use of
1385+
/// `const { ... }` syntax.
1386+
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Walkable)]
1387+
pub enum MgcaDisambiguation {
1388+
AnonConst,
1389+
Direct,
1390+
}
1391+
13881392
/// A constant (expression) that's not an item or associated item,
13891393
/// but needs its own `DefId` for type-checking, const-eval, etc.
13901394
/// These are usually found nested inside types (e.g., array lengths)
@@ -1394,6 +1398,7 @@ pub enum UnsafeSource {
13941398
pub struct AnonConst {
13951399
pub id: NodeId,
13961400
pub value: Box<Expr>,
1401+
pub mgca_disambiguation: MgcaDisambiguation,
13971402
}
13981403

13991404
/// An expression.
@@ -1412,26 +1417,20 @@ impl Expr {
14121417
///
14131418
/// This will unwrap at most one block level (curly braces). After that, if the expression
14141419
/// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`].
1415-
/// See there for more info about `allow_mgca_arg`.
14161420
///
1417-
/// The only additional thing to note is that when `allow_mgca_arg` is false, this function
1418-
/// will only allow paths with no qself, before dispatching to the `Path` function of
1419-
/// the same name.
1421+
/// This function will only allow paths with no qself, before dispatching to the `Path`
1422+
/// function of the same name.
14201423
///
14211424
/// Does not ensure that the path resolves to a const param/item, the caller should check this.
14221425
/// This also does not consider macros, so it's only correct after macro-expansion.
1423-
pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool {
1426+
pub fn is_potential_trivial_const_arg(&self) -> bool {
14241427
let this = self.maybe_unwrap_block();
1425-
if allow_mgca_arg {
1426-
matches!(this.kind, ExprKind::Path(..))
1428+
if let ExprKind::Path(None, path) = &this.kind
1429+
&& path.is_potential_trivial_const_arg()
1430+
{
1431+
true
14271432
} else {
1428-
if let ExprKind::Path(None, path) = &this.kind
1429-
&& path.is_potential_trivial_const_arg(allow_mgca_arg)
1430-
{
1431-
true
1432-
} else {
1433-
false
1434-
}
1433+
false
14351434
}
14361435
}
14371436

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ macro_rules! common_visitor_and_walkers {
415415
UnsafeBinderCastKind,
416416
BinOpKind,
417417
BlockCheckMode,
418+
MgcaDisambiguation,
418419
BorrowKind,
419420
BoundAsyncness,
420421
BoundConstness,

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
484484
arg
485485
};
486486

487-
let anon_const = AnonConst { id: node_id, value: const_value };
487+
let anon_const = AnonConst {
488+
id: node_id,
489+
value: const_value,
490+
mgca_disambiguation: MgcaDisambiguation::AnonConst,
491+
};
488492
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
489493
} else {
490494
real_args.push(arg);

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12061206
.and_then(|partial_res| partial_res.full_res())
12071207
{
12081208
if !res.matches_ns(Namespace::TypeNS)
1209-
&& path.is_potential_trivial_const_arg(false)
1209+
&& path.is_potential_trivial_const_arg()
12101210
{
12111211
debug!(
12121212
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -2275,11 +2275,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
22752275
) -> &'hir hir::ConstArg<'hir> {
22762276
let tcx = self.tcx;
22772277

2278-
let ct_kind = if path
2279-
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
2280-
&& (tcx.features().min_generic_const_args()
2281-
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
2282-
{
2278+
let is_trivial_path = path.is_potential_trivial_const_arg()
2279+
&& matches!(res, Res::Def(DefKind::ConstParam, _));
2280+
let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() {
22832281
let qpath = self.lower_qpath(
22842282
ty_id,
22852283
&None,
@@ -2358,6 +2356,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23582356
}
23592357
}
23602358

2359+
#[instrument(level = "debug", skip(self), ret)]
2360+
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
2361+
let overly_complex_const = |this: &mut Self| {
2362+
let e = this.dcx().struct_span_err(
2363+
expr.span,
2364+
"complex const arguments must be placed inside of a `const` block",
2365+
);
2366+
2367+
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
2368+
};
2369+
2370+
match &expr.kind {
2371+
ExprKind::Path(qself, path) => {
2372+
let qpath = self.lower_qpath(
2373+
expr.id,
2374+
qself,
2375+
path,
2376+
ParamMode::Explicit,
2377+
AllowReturnTypeNotation::No,
2378+
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
2379+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
2380+
None,
2381+
);
2382+
2383+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
2384+
}
2385+
ExprKind::Underscore => ConstArg {
2386+
hir_id: self.lower_node_id(expr.id),
2387+
kind: hir::ConstArgKind::Infer(expr.span, ()),
2388+
},
2389+
ExprKind::Block(block, _) => {
2390+
if let [stmt] = block.stmts.as_slice()
2391+
&& let StmtKind::Expr(expr) = &stmt.kind
2392+
&& matches!(
2393+
expr.kind,
2394+
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
2395+
)
2396+
{
2397+
return self.lower_expr_to_const_arg_direct(expr);
2398+
}
2399+
2400+
overly_complex_const(self)
2401+
}
2402+
_ => overly_complex_const(self),
2403+
}
2404+
}
2405+
23612406
/// See [`hir::ConstArg`] for when to use this function vs
23622407
/// [`Self::lower_anon_const_to_anon_const`].
23632408
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
@@ -2367,6 +2412,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23672412
#[instrument(level = "debug", skip(self))]
23682413
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
23692414
let tcx = self.tcx;
2415+
2416+
// We cannot change parsing depending on feature gates available,
2417+
// we can only require feature gates to be active as a delayed check.
2418+
// Thus we just parse anon consts generally and make the real decision
2419+
// making in ast lowering.
2420+
// FIXME(min_generic_const_args): revisit once stable
2421+
if tcx.features().min_generic_const_args() {
2422+
return match anon.mgca_disambiguation {
2423+
MgcaDisambiguation::AnonConst => {
2424+
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
2425+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
2426+
}
2427+
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
2428+
};
2429+
}
2430+
23702431
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
23712432
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
23722433
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
@@ -2378,20 +2439,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23782439
} else {
23792440
&anon.value
23802441
};
2442+
23812443
let maybe_res =
23822444
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
23832445
if let ExprKind::Path(qself, path) = &expr.kind
2384-
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
2385-
&& (tcx.features().min_generic_const_args()
2386-
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
2446+
&& path.is_potential_trivial_const_arg()
2447+
&& matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
23872448
{
23882449
let qpath = self.lower_qpath(
23892450
expr.id,
23902451
qself,
23912452
path,
23922453
ParamMode::Explicit,
23932454
AllowReturnTypeNotation::No,
2394-
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
23952455
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
23962456
None,
23972457
);

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
509509
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
510510
gate_all!(postfix_match, "postfix match is experimental");
511511
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
512+
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
512513
gate_all!(global_registration, "global registration is experimental");
513514
gate_all!(return_type_notation, "return type notation is experimental");
514515
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");

compiler/rustc_builtin_macros/src/autodiff.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod llvm_enzyme {
1717
use rustc_ast::{
1818
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemKind, BindingMode,
1919
FnRetTy, FnSig, GenericArg, GenericArgs, GenericParamKind, Generics, ItemKind,
20-
MetaItemInner, PatKind, Path, PathSegment, TyKind, Visibility,
20+
MetaItemInner, MgcaDisambiguation, PatKind, Path, PathSegment, TyKind, Visibility,
2121
};
2222
use rustc_expand::base::{Annotatable, ExtCtxt};
2323
use rustc_span::{Ident, Span, Symbol, sym};
@@ -558,7 +558,11 @@ mod llvm_enzyme {
558558
}
559559
GenericParamKind::Const { .. } => {
560560
let expr = ecx.expr_path(ast::Path::from_ident(p.ident));
561-
let anon_const = AnonConst { id: ast::DUMMY_NODE_ID, value: expr };
561+
let anon_const = AnonConst {
562+
id: ast::DUMMY_NODE_ID,
563+
value: expr,
564+
mgca_disambiguation: MgcaDisambiguation::Direct,
565+
};
562566
Some(AngleBracketedArg::Arg(GenericArg::Const(anon_const)))
563567
}
564568
GenericParamKind::Lifetime { .. } => None,
@@ -813,6 +817,7 @@ mod llvm_enzyme {
813817
let anon_const = rustc_ast::AnonConst {
814818
id: ast::DUMMY_NODE_ID,
815819
value: ecx.expr_usize(span, 1 + x.width as usize),
820+
mgca_disambiguation: MgcaDisambiguation::Direct,
816821
};
817822
TyKind::Array(ty.clone(), anon_const)
818823
};
@@ -827,6 +832,7 @@ mod llvm_enzyme {
827832
let anon_const = rustc_ast::AnonConst {
828833
id: ast::DUMMY_NODE_ID,
829834
value: ecx.expr_usize(span, x.width as usize),
835+
mgca_disambiguation: MgcaDisambiguation::Direct,
830836
};
831837
let kind = TyKind::Array(ty.clone(), anon_const);
832838
let ty =

compiler/rustc_builtin_macros/src/pattern_type.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::tokenstream::TokenStream;
2-
use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast, token};
2+
use rustc_ast::{AnonConst, DUMMY_NODE_ID, MgcaDisambiguation, Ty, TyPat, TyPatKind, ast, token};
33
use rustc_errors::PResult;
44
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
55
use rustc_parse::exp;
@@ -60,8 +60,20 @@ fn ty_pat(kind: TyPatKind, span: Span) -> TyPat {
6060
fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> TyPat {
6161
let kind = match pat.kind {
6262
ast::PatKind::Range(start, end, include_end) => TyPatKind::Range(
63-
start.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
64-
end.map(|value| Box::new(AnonConst { id: DUMMY_NODE_ID, value })),
63+
start.map(|value| {
64+
Box::new(AnonConst {
65+
id: DUMMY_NODE_ID,
66+
value,
67+
mgca_disambiguation: MgcaDisambiguation::Direct,
68+
})
69+
}),
70+
end.map(|value| {
71+
Box::new(AnonConst {
72+
id: DUMMY_NODE_ID,
73+
value,
74+
mgca_disambiguation: MgcaDisambiguation::Direct,
75+
})
76+
}),
6577
include_end,
6678
),
6779
ast::PatKind::Or(variants) => {

compiler/rustc_expand/src/build.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use rustc_ast::token::Delimiter;
22
use rustc_ast::tokenstream::TokenStream;
33
use rustc_ast::util::literal;
44
use rustc_ast::{
5-
self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind,
6-
UnOp, attr, token, tokenstream,
5+
self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind,
6+
MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream,
77
};
88
use rustc_span::source_map::Spanned;
99
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -101,6 +101,7 @@ impl<'a> ExtCtxt<'a> {
101101
attrs: AttrVec::new(),
102102
tokens: None,
103103
}),
104+
mgca_disambiguation: MgcaDisambiguation::Direct,
104105
}
105106
}
106107

compiler/rustc_parse/src/parser/asm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc_ast::{self as ast, AsmMacro};
1+
use rustc_ast::{self as ast, AsmMacro, MgcaDisambiguation};
22
use rustc_span::{Span, Symbol, kw};
33

44
use super::{ExpKeywordPair, ForceCollect, IdentIsRaw, Trailing, UsePreAttrPos};
@@ -149,7 +149,7 @@ fn parse_asm_operand<'a>(
149149
let block = p.parse_block()?;
150150
ast::InlineAsmOperand::Label { block }
151151
} else if p.eat_keyword(exp!(Const)) {
152-
let anon_const = p.parse_expr_anon_const()?;
152+
let anon_const = p.parse_expr_anon_const(|_, _| MgcaDisambiguation::AnonConst)?;
153153
ast::InlineAsmOperand::Const { anon_const }
154154
} else if p.eat_keyword(exp!(Sym)) {
155155
let expr = p.parse_expr()?;

0 commit comments

Comments
 (0)