Skip to content

Commit acc3a0e

Browse files
committed
Syntactically distinguish anon const const args
1 parent 2a3a62d commit acc3a0e

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

+779
-252
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
@@ -489,7 +489,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
489489
arg
490490
};
491491

492-
let anon_const = AnonConst { id: node_id, value: const_value };
492+
let anon_const = AnonConst {
493+
id: node_id,
494+
value: const_value,
495+
mgca_disambiguation: MgcaDisambiguation::AnonConst,
496+
};
493497
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
494498
} else {
495499
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
@@ -1219,7 +1219,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12191219
.and_then(|partial_res| partial_res.full_res())
12201220
{
12211221
if !res.matches_ns(Namespace::TypeNS)
1222-
&& path.is_potential_trivial_const_arg(false)
1222+
&& path.is_potential_trivial_const_arg()
12231223
{
12241224
debug!(
12251225
"lower_generic_arg: Lowering type argument as const argument: {:?}",
@@ -2287,11 +2287,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
22872287
) -> &'hir hir::ConstArg<'hir> {
22882288
let tcx = self.tcx;
22892289

2290-
let ct_kind = if path
2291-
.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
2292-
&& (tcx.features().min_generic_const_args()
2293-
|| matches!(res, Res::Def(DefKind::ConstParam, _)))
2294-
{
2290+
let is_trivial_path = path.is_potential_trivial_const_arg()
2291+
&& matches!(res, Res::Def(DefKind::ConstParam, _));
2292+
let ct_kind = if is_trivial_path || tcx.features().min_generic_const_args() {
22952293
let qpath = self.lower_qpath(
22962294
ty_id,
22972295
&None,
@@ -2370,6 +2368,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23702368
}
23712369
}
23722370

2371+
#[instrument(level = "debug", skip(self), ret)]
2372+
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
2373+
let overly_complex_const = |this: &mut Self| {
2374+
let e = this.dcx().struct_span_err(
2375+
expr.span,
2376+
"complex const arguments must be placed inside of a `const` block",
2377+
);
2378+
2379+
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
2380+
};
2381+
2382+
match &expr.kind {
2383+
ExprKind::Path(qself, path) => {
2384+
let qpath = self.lower_qpath(
2385+
expr.id,
2386+
qself,
2387+
path,
2388+
ParamMode::Explicit,
2389+
AllowReturnTypeNotation::No,
2390+
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
2391+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
2392+
None,
2393+
);
2394+
2395+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
2396+
}
2397+
ExprKind::Underscore => ConstArg {
2398+
hir_id: self.lower_node_id(expr.id),
2399+
kind: hir::ConstArgKind::Infer(expr.span, ()),
2400+
},
2401+
ExprKind::Block(block, _) => {
2402+
if let [stmt] = block.stmts.as_slice()
2403+
&& let StmtKind::Expr(expr) = &stmt.kind
2404+
&& matches!(
2405+
expr.kind,
2406+
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
2407+
)
2408+
{
2409+
return self.lower_expr_to_const_arg_direct(expr);
2410+
}
2411+
2412+
overly_complex_const(self)
2413+
}
2414+
_ => overly_complex_const(self),
2415+
}
2416+
}
2417+
23732418
/// See [`hir::ConstArg`] for when to use this function vs
23742419
/// [`Self::lower_anon_const_to_anon_const`].
23752420
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> {
23792424
#[instrument(level = "debug", skip(self))]
23802425
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
23812426
let tcx = self.tcx;
2427+
2428+
// We cannot change parsing depending on feature gates available,
2429+
// we can only require feature gates to be active as a delayed check.
2430+
// Thus we just parse anon consts generally and make the real decision
2431+
// making in ast lowering.
2432+
// FIXME(min_generic_const_args): revisit once stable
2433+
if tcx.features().min_generic_const_args() {
2434+
return match anon.mgca_disambiguation {
2435+
MgcaDisambiguation::AnonConst => {
2436+
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
2437+
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
2438+
}
2439+
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
2440+
};
2441+
}
2442+
23822443
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
23832444
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
23842445
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
@@ -2390,20 +2451,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23902451
} else {
23912452
&anon.value
23922453
};
2454+
23932455
let maybe_res =
23942456
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
23952457
if let ExprKind::Path(qself, path) = &expr.kind
2396-
&& path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args())
2397-
&& (tcx.features().min_generic_const_args()
2398-
|| matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _))))
2458+
&& path.is_potential_trivial_const_arg()
2459+
&& matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
23992460
{
24002461
let qpath = self.lower_qpath(
24012462
expr.id,
24022463
qself,
24032464
path,
24042465
ParamMode::Explicit,
24052466
AllowReturnTypeNotation::No,
2406-
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
24072467
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
24082468
None,
24092469
);

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
517517
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
518518
gate_all!(postfix_match, "postfix match is experimental");
519519
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
520+
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
520521
gate_all!(global_registration, "global registration is experimental");
521522
gate_all!(return_type_notation, "return type notation is experimental");
522523
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)