Skip to content

Commit 4c4aeb6

Browse files
authored
Unrolled build for #150823
Rollup merge of #150823 - camelid:ogca, r=BoxyUwU Implement MVP for opaque generic const arguments This is meant to be the interim successor to generic const expressions. Essentially, const item RHS's will be allowed to do arbitrary const operations using generics. The limitation is that these const items will be treated opaquely, like ADTs in nominal typing, such that uses of them will only be equal if the same const item is referenced. In other words, two const items with the exact same RHS will not be considered equal. I also added some logic to check feature gates that depend on others being enabled (like oGCA depending on mGCA). ### Coherence During coherence, OGCA consts should be normalized ambiguously because they are opaque but eventually resolved to a real value. We don't want two OGCAs that have the same value to be treated as distinct for coherence purposes. (Just like opaque types.) This actually doesn't work yet because there are pre-existing fundamental issues with equate relations involving consts that need to be normalized. The problem is that we normalize only one layer of the const item and don't actually process the resulting anon const. Normally the created inference variable should be handled, which in this case would cause us to hit the anon const, but that's not happening. Specifically, `visit_const` on `Generalizer` should be updated to be similar to `visit_ty`. r? @BoxyUwU
2 parents 39219ce + 9a30ec8 commit 4c4aeb6

48 files changed

Lines changed: 347 additions & 53 deletions

File tree

Some content is hidden

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

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,16 @@ pub(crate) struct IncompatibleFeatures {
950950
pub f2: Symbol,
951951
}
952952

953+
#[derive(Diagnostic)]
954+
#[diag("`{$parent}` requires {$missing} to be enabled")]
955+
#[help("enable all of these features")]
956+
pub(crate) struct MissingDependentFeatures {
957+
#[primary_span]
958+
pub parent_span: Span,
959+
pub parent: Symbol,
960+
pub missing: String,
961+
}
962+
953963
#[derive(Diagnostic)]
954964
#[diag("negative bounds are not supported")]
955965
pub(crate) struct NegativeBoundUnsupported {

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
441441
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
442442
maybe_stage_features(sess, features, krate);
443443
check_incompatible_features(sess, features);
444+
check_dependent_features(sess, features);
444445
check_new_solver_banned_features(sess, features);
445446

446447
let mut visitor = PostExpansionVisitor { sess, features };
@@ -649,6 +650,27 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
649650
}
650651
}
651652

653+
fn check_dependent_features(sess: &Session, features: &Features) {
654+
for &(parent, children) in
655+
rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent))
656+
{
657+
if children.iter().any(|f| !features.enabled(*f)) {
658+
let parent_span = features
659+
.enabled_features_iter_stable_order()
660+
.find_map(|(name, span)| (name == parent).then_some(span))
661+
.unwrap();
662+
// FIXME: should probably format this in fluent instead of here
663+
let missing = children
664+
.iter()
665+
.filter(|f| !features.enabled(**f))
666+
.map(|s| format!("`{}`", s.as_str()))
667+
.intersperse(String::from(", "))
668+
.collect();
669+
sess.dcx().emit_err(errors::MissingDependentFeatures { parent_span, parent, missing });
670+
}
671+
}
672+
}
673+
652674
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
653675
if !sess.opts.unstable_opts.next_solver.globally {
654676
return;

compiler/rustc_ast_passes/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// tidy-alphabetical-start
66
#![feature(box_patterns)]
77
#![feature(if_let_guard)]
8+
#![feature(iter_intersperse)]
89
#![feature(iter_is_partitioned)]
910
// tidy-alphabetical-end
1011

compiler/rustc_feature/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,6 @@ pub use builtin_attrs::{
136136
};
137137
pub use removed::REMOVED_LANG_FEATURES;
138138
pub use unstable::{
139-
EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES,
139+
DEPENDENT_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES,
140+
UNSTABLE_LANG_FEATURES,
140141
};

compiler/rustc_feature/src/unstable.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,8 @@ declare_features! (
605605
(unstable, offset_of_enum, "1.75.0", Some(120141)),
606606
/// Allows using fields with slice type in offset_of!
607607
(unstable, offset_of_slice, "1.81.0", Some(126151)),
608+
/// Allows using generics in more complex const expressions, based on definitional equality.
609+
(unstable, opaque_generic_const_args, "CURRENT_RUSTC_VERSION", Some(151972)),
608610
/// Allows using `#[optimize(X)]`.
609611
(unstable, optimize_attribute, "1.34.0", Some(54882)),
610612
/// Allows specifying nop padding on functions for dynamic patching.
@@ -782,3 +784,9 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[
782784
// boolean logic required to tell which typing rules to use.
783785
(sym::ref_pat_eat_one_layer_2024, sym::ref_pat_eat_one_layer_2024_structural),
784786
];
787+
788+
/// Some features require one or more other features to be enabled.
789+
pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[
790+
(sym::opaque_generic_const_args, &[sym::min_generic_const_args]),
791+
(sym::unsized_const_params, &[sym::adt_const_params]),
792+
];

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
1717
use std::cell::Cell;
1818
use std::iter;
19-
use std::ops::Bound;
19+
use std::ops::{Bound, ControlFlow};
2020

2121
use rustc_abi::{ExternAbi, Size};
2222
use rustc_ast::Recovered;
@@ -26,12 +26,13 @@ use rustc_errors::{
2626
Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey, struct_span_code_err,
2727
};
2828
use rustc_hir::attrs::AttributeKind;
29-
use rustc_hir::def::DefKind;
29+
use rustc_hir::def::{DefKind, Res};
3030
use rustc_hir::def_id::{DefId, LocalDefId};
31-
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt};
31+
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
3232
use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind, find_attr};
3333
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3434
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
35+
use rustc_middle::hir::nested_filter;
3536
use rustc_middle::query::Providers;
3637
use rustc_middle::ty::util::{Discr, IntTypeExt};
3738
use rustc_middle::ty::{
@@ -1511,6 +1512,20 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
15111512
let parent_hir_node = tcx.hir_node(tcx.parent_hir_id(const_arg_id));
15121513
if tcx.features().generic_const_exprs() {
15131514
ty::AnonConstKind::GCE
1515+
} else if tcx.features().opaque_generic_const_args() {
1516+
// Only anon consts that are the RHS of a const item can be OGCA.
1517+
// Note: We can't just check tcx.parent because it needs to be EXACTLY
1518+
// the RHS, not just part of the RHS.
1519+
if !is_anon_const_rhs_of_const_item(tcx, def) {
1520+
return ty::AnonConstKind::MCG;
1521+
}
1522+
1523+
let body = tcx.hir_body_owned_by(def);
1524+
let mut visitor = OGCAParamVisitor(tcx);
1525+
match visitor.visit_body(body) {
1526+
ControlFlow::Break(UsesParam) => ty::AnonConstKind::OGCA,
1527+
ControlFlow::Continue(()) => ty::AnonConstKind::MCG,
1528+
}
15141529
} else if tcx.features().min_generic_const_args() {
15151530
ty::AnonConstKind::MCG
15161531
} else if let hir::Node::Expr(hir::Expr {
@@ -1528,6 +1543,49 @@ fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKin
15281543
}
15291544
}
15301545

1546+
fn is_anon_const_rhs_of_const_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
1547+
let hir_id = tcx.local_def_id_to_hir_id(def_id);
1548+
let Some((_, grandparent_node)) = tcx.hir_parent_iter(hir_id).nth(1) else { return false };
1549+
let (Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, _, ct_rhs), .. })
1550+
| Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(_, ct_rhs), .. })
1551+
| Node::TraitItem(hir::TraitItem {
1552+
kind: hir::TraitItemKind::Const(_, Some(ct_rhs)), ..
1553+
})) = grandparent_node
1554+
else {
1555+
return false;
1556+
};
1557+
let hir::ConstItemRhs::TypeConst(hir::ConstArg {
1558+
kind: hir::ConstArgKind::Anon(rhs_anon), ..
1559+
}) = ct_rhs
1560+
else {
1561+
return false;
1562+
};
1563+
def_id == rhs_anon.def_id
1564+
}
1565+
1566+
struct OGCAParamVisitor<'tcx>(TyCtxt<'tcx>);
1567+
1568+
struct UsesParam;
1569+
1570+
impl<'tcx> Visitor<'tcx> for OGCAParamVisitor<'tcx> {
1571+
type NestedFilter = nested_filter::OnlyBodies;
1572+
type Result = ControlFlow<UsesParam>;
1573+
1574+
fn maybe_tcx(&mut self) -> TyCtxt<'tcx> {
1575+
self.0
1576+
}
1577+
1578+
fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: HirId) -> ControlFlow<UsesParam> {
1579+
if let Res::Def(DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, _) =
1580+
path.res
1581+
{
1582+
return ControlFlow::Break(UsesParam);
1583+
}
1584+
1585+
intravisit::walk_path(self, path)
1586+
}
1587+
}
1588+
15311589
#[instrument(level = "debug", skip(tcx), ret)]
15321590
fn const_of_item<'tcx>(
15331591
tcx: TyCtxt<'tcx>,

compiler/rustc_hir_analysis/src/collect/generics_of.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
9292
match tcx.anon_const_kind(def_id) {
9393
// Stable: anon consts are not able to use any generic parameters...
9494
ty::AnonConstKind::MCG => None,
95+
// OGCA anon consts inherit their parent's generics.
96+
ty::AnonConstKind::OGCA => Some(parent_did),
9597
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
9698
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
9799

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,11 @@ impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
404404
diag.span_note(impl_.self_ty.span, "not a concrete type");
405405
}
406406
}
407+
if self.tcx.features().min_generic_const_args()
408+
&& !self.tcx.features().opaque_generic_const_args()
409+
{
410+
diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items");
411+
}
407412
diag.emit()
408413
}
409414
}

compiler/rustc_middle/src/ty/consts.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::Cow;
22

33
use rustc_data_structures::intern::Interned;
44
use rustc_error_messages::MultiSpan;
5-
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
5+
use rustc_macros::HashStable;
66
use rustc_type_ir::walk::TypeWalker;
77
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
88

@@ -335,16 +335,3 @@ impl<'tcx> Const<'tcx> {
335335
TypeWalker::new(self.into())
336336
}
337337
}
338-
339-
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
340-
pub enum AnonConstKind {
341-
/// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope
342-
GCE,
343-
/// stable `min_const_generics` anon consts are not allowed to use any generic parameters
344-
MCG,
345-
/// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters
346-
/// but must not depend on the actual instantiation. See #76200 for more information
347-
RepeatExprCount,
348-
/// anon consts outside of the type system, e.g. enum discriminants
349-
NonTypeSystem,
350-
}

compiler/rustc_middle/src/ty/context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
238238
fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
239239
self.const_of_item(def_id)
240240
}
241+
fn anon_const_kind(self, def_id: DefId) -> ty::AnonConstKind {
242+
self.anon_const_kind(def_id)
243+
}
241244

242245
type AdtDef = ty::AdtDef<'tcx>;
243246
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {

0 commit comments

Comments
 (0)