Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f7548dd
Stabilize `funnel_shifts` (including `const`)
tgross35 Aug 13, 2026
1bd00d4
Add support for -Zsanitizer-cfi-minimal-runtime
jakos-sec Sep 1, 2026
4d68be3
minor cleanup for minimal runtime test
jakos-sec Sep 10, 2026
855d8a2
Add target modifier for -Zsanitizer-cfi-minimal-runtime
jakos-sec Sep 10, 2026
a42ab2f
Make -Zsanitizer-cfi-minimal-runtime also dependent on -Zsanitizer=cfi
jakos-sec Sep 11, 2026
bba4a3f
Fix tests with new cfi-minimal-runtime target modifier
jakos-sec Sep 11, 2026
775c187
Fix linter issue in diagnostics.rs
jakos-sec Sep 11, 2026
3058339
Fix broken test introduced by cfi-minimal-runtime target modifier
jakos-sec Sep 11, 2026
7aacc8a
Skip gcc for CFI runtime tests
jakos-sec Sep 11, 2026
8e5ad6c
use match to determine correct ubsan cfi handler
jakos-sec Sep 21, 2026
20b6fd6
Address review feedback
jakos-sec Sep 23, 2026
f3b4f0f
Stabilize `Result::into_{ok,err}`
theemathas Aug 25, 2026
a579f7e
Add -Ctarget-feature=-crt-static to CFI minimal runtime tests
jakos-sec Sep 25, 2026
0879316
Limit CFI run-make test to Linux
jakos-sec Sep 26, 2026
01d2c40
add automatically_derived documentation
conferatur Sep 26, 2026
9e8ca58
implement #![feature(gca_adts)]
khyperia Sep 28, 2026
773ad19
Add `stable_rustc` helper in `run-make-support`
Kobzol Sep 28, 2026
62ce017
Allow using different index types when reading and writing to tables
aerooneqq Sep 28, 2026
48b2592
do not complain about unstable target features on nightly
RalfJung Sep 28, 2026
b89cf31
Stabilize vec_try_remove
petrak-at-canonical Sep 28, 2026
475b967
Rollup merge of #161015 - tgross35:stabilize-funnel-shifts, r=nia-e
tgross35 Sep 29, 2026
4426dcd
Rollup merge of #161712 - theemathas:stab-into-ok-err, r=nia-e
tgross35 Sep 29, 2026
538a927
Rollup merge of #162493 - jakos-sec:ubsan-runtime-minimal, r=rcvalle
tgross35 Sep 29, 2026
e7ac0de
Rollup merge of #163427 - khyperia:gca-adts, r=BoxyUwU
tgross35 Sep 29, 2026
9a0bca0
Rollup merge of #163390 - conferatur:add-automatically-derived-attrib…
tgross35 Sep 29, 2026
5365b21
Rollup merge of #163428 - RalfJung:unstable-target-feature, r=petroch…
tgross35 Sep 29, 2026
41d560b
Rollup merge of #163444 - Kobzol:run-make-stable-benchmarks, r=jieyouxu
tgross35 Sep 29, 2026
2e42eed
Rollup merge of #163447 - aerooneqq:two-sided-index-in-metadata, r=pe…
tgross35 Sep 29, 2026
a8ead4a
Rollup merge of #163459 - petrak-at-canonical:vec-try-remove, r=hanna…
tgross35 Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3626,6 +3626,7 @@ dependencies = [
name = "rustc_ast_lowering"
version = "0.0.0"
dependencies = [
"bitflags",
"rustc_abi",
"rustc_ast",
"rustc_attr_ir",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
#![allow(clippy::mut_from_ref)] // Arena allocators are one place where this pattern is fine.
#![allow(internal_features)]
#![cfg_attr(bootstrap, feature(never_type))]
#![cfg_attr(bootstrap, feature(unwrap_infallible))]
#![cfg_attr(test, feature(test))]
#![deny(unsafe_op_in_unsafe_fn)]
#![doc(test(no_crate_inject, attr(deny(warnings))))]
#![feature(decl_macro)]
#![feature(dropck_eyepatch)]
#![feature(rustc_attrs)]
#![feature(unwrap_infallible)]
// tidy-alphabetical-end

use std::alloc::Layout;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ doctest = false

[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_attr_ir = { path = "../rustc_attr_ir" }
Expand Down
149 changes: 98 additions & 51 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use rustc_data_structures::steal::Steal;
use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::codes::*;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, ErrorGuaranteed};
use rustc_hir::def::{DefKind, Namespace, PerNS, Res};
use rustc_hir::def::{CtorKind, DefKind, Namespace, PerNS, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
use rustc_hir::definitions::PerParentDisambiguatorState;
use rustc_hir::lints::DelayedLint;
Expand Down Expand Up @@ -1420,10 +1420,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ct = self.arena.alloc(ct);
return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
}
TyKind::GcaMacro(expr) if self.tcx.features().gca_min_const_items() => {
TyKind::GcaMacro(expr) if self.tcx.features().gca() => {
let ct = match self.can_lower_expr_to_const_arg_direct(
expr,
DirectConstArgContext::MacrolessMinGenericConstArgs,
self.direct_const_arg_context_enabled_by_gca_macro(),
) {
Ok(()) => self.lower_expr_to_const_arg_direct(expr, None),
Err(e) => e.emit(self),
Expand Down Expand Up @@ -2628,18 +2628,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span,
) -> hir::ConstItemRhs<'hir> {
let is_direct = |body| {
if self.tcx.features().gca_macroless_items() {
self.can_lower_expr_to_const_arg_direct(
body,
DirectConstArgContext::MacrolessMinGenericConstArgs,
)
.is_ok()
let context = if self.tcx.features().gca_macroless_items() {
self.direct_const_arg_context_enabled_by_gca_macro()
} else {
// do not check can_lower_expr_to_const_arg_direct, but rather just
// ExprKind::GcaMacro, because we don't want e.g.
// `impl<const N: u8> { const C: u8 = N; }` to be a direct-rhs const
matches!(body, Expr { kind: ExprKind::GcaMacro(_), .. })
}
DirectConstArgContext::GCA_MACRO
};
self.can_lower_expr_to_const_arg_direct(body, context).is_ok()
};
if self.tcx.features().gca_min_const_items()
&& let Some(body) = body
Expand All @@ -2653,13 +2647,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

fn direct_const_arg_context_enabled_by_gca_macro(&self) -> DirectConstArgContext {
let mut result = DirectConstArgContext::GCA_BASE_FEATURES;
if self.tcx.features().gca_min_const_items() {
result |= DirectConstArgContext::GCA_MIN_CONST_ITEMS;
}
if self.tcx.features().gca_adts() {
result |= DirectConstArgContext::GCA_ADTS;
}
result
}

/// Only valid for const *arg* contexts, not const *item* contexts.
fn ambient_direct_const_arg_context(&self) -> DirectConstArgContext {
if self.tcx.features().gca_macroless_args() {
DirectConstArgContext::MacrolessMinGenericConstArgs
} else if self.tcx.features().gca_min_const_items() {
DirectConstArgContext::MinGenericConstArgs
self.direct_const_arg_context_enabled_by_gca_macro()
} else if self.tcx.features().gca() {
DirectConstArgContext::GCA
} else {
DirectConstArgContext::Stable
DirectConstArgContext::STABLE
}
}

Expand All @@ -2671,9 +2677,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
res: Option<Res<NodeId>>,
context: DirectConstArgContext,
) -> Result<(), UnrepresentableConstArgError> {
if let DirectConstArgContext::MacrolessMinGenericConstArgs = context {
if context.contains(DirectConstArgContext::PATH_ANY) {
Ok(())
} else if context.contains(DirectConstArgContext::PATH_CONST_CTOR)
&& matches!(res, Some(Res::Def(DefKind::Ctor(_, CtorKind::Const), _)))
{
// FIXME(gca_adts): This check is incomplete. Type-relative paths and other complicating
// factors make things very difficult - e.g. `<Option<T>>::None`
Ok(())
} else if qself.is_none()
} else if context.contains(DirectConstArgContext::PATH_PLAIN_PARAM)
&& qself.is_none()
&& path.is_single_argless_ident()
&& matches!(res, Some(Res::Def(DefKind::ConstParam, _)))
{
Expand All @@ -2689,59 +2702,61 @@ impl<'hir> LoweringContext<'_, 'hir> {
expr: &Expr,
context: DirectConstArgContext,
) -> Result<(), UnrepresentableConstArgError> {
use DirectConstArgContext::*;
// Note the only stable case is currently ExprKind::Path
match (&expr.kind, context) {
(
ExprKind::Call(Expr { kind: ExprKind::Path(_, _), .. }, args),
MacrolessMinGenericConstArgs,
) => {
match &expr.kind {
ExprKind::Call(Expr { kind: ExprKind::Path(_, _), .. }, args)
if context.contains(DirectConstArgContext::TUPLE_CALL) =>
{
for arg in args {
self.can_lower_expr_to_const_arg_direct(arg, context)?;
}
Ok(())
}
(ExprKind::Tup(exprs), MacrolessMinGenericConstArgs) => {
ExprKind::Tup(exprs) if context.contains(DirectConstArgContext::TUPLE) => {
for expr in exprs {
self.can_lower_expr_to_const_arg_direct(expr, context)?;
}
Ok(())
}
(ExprKind::Path(qself, path), _) => {
ExprKind::Path(qself, path) => {
let res =
self.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
self.can_lower_path_to_const_arg_direct(qself, path, expr.span, res, context)
}
(ExprKind::Struct(se), MacrolessMinGenericConstArgs) => {
ExprKind::Struct(se) if context.contains(DirectConstArgContext::STRUCT) => {
for f in &se.fields {
self.can_lower_expr_to_const_arg_direct(&f.expr, context)?;
}
Ok(())
}
(ExprKind::Array(elements), MacrolessMinGenericConstArgs) => {
ExprKind::Array(elements) if context.contains(DirectConstArgContext::ARRAY) => {
for element in elements {
self.can_lower_expr_to_const_arg_direct(element, context)?;
}
Ok(())
}
(ExprKind::Underscore, MacrolessMinGenericConstArgs) => Ok(()),
(ExprKind::Paren(expr), MacrolessMinGenericConstArgs) => {
ExprKind::Underscore if context.contains(DirectConstArgContext::UNDERSCORE) => Ok(()),
ExprKind::Paren(expr) if context.contains(DirectConstArgContext::PAREN) => {
self.can_lower_expr_to_const_arg_direct(expr, context)
}
(ExprKind::Block(block, _), MacrolessMinGenericConstArgs)
if let [stmt] = block.stmts.as_slice()
ExprKind::Block(block, _)
if context.contains(DirectConstArgContext::BLOCK)
&& let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind =>
{
self.can_lower_expr_to_const_arg_direct(expr, context)
}
(ExprKind::Lit(_), MacrolessMinGenericConstArgs) => Ok(()),
(ExprKind::Unary(UnOp::Neg, inner_expr), MacrolessMinGenericConstArgs)
if let ExprKind::Lit(_) = &inner_expr.kind =>
ExprKind::Lit(_) if context.contains(DirectConstArgContext::LIT) => Ok(()),
ExprKind::Unary(UnOp::Neg, inner_expr)
if context.contains(DirectConstArgContext::LIT)
&& let ExprKind::Lit(_) = &inner_expr.kind =>
{
Ok(())
}
(ExprKind::ConstBlock(_), MacrolessMinGenericConstArgs) => Ok(()),
(ExprKind::GcaMacro(_), MacrolessMinGenericConstArgs | MinGenericConstArgs) => {
ExprKind::ConstBlock(_) if context.contains(DirectConstArgContext::CONST_BLOCK) => {
Ok(())
}
ExprKind::GcaMacro(_) if context.contains(DirectConstArgContext::GCA_MACRO) => {
// Always report this as able to be represented directly. If it turns out not to be,
// `lower_expr_to_const_arg_direct` will report an error.
Ok(())
Expand Down Expand Up @@ -2927,11 +2942,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `can_lower_expr_to_const_arg_direct` always returns success upon encountering a
// ExprKind::GcaMacro, which effectively forces the expression to be lowered as a
// direct arg. If it actually turns out to not be possible, emit an error instead.
// Always use MacrolessMinGenericConstArgs, even if we're under regular GCA, because
// that's what the macro means: to enter a context that is like macroless GCA.
match self.can_lower_expr_to_const_arg_direct(
expr,
DirectConstArgContext::MacrolessMinGenericConstArgs,
self.direct_const_arg_context_enabled_by_gca_macro(),
) {
Ok(()) => self.lower_expr_to_const_arg_direct(expr, id_override),
Err(err) => err.emit(self),
Expand Down Expand Up @@ -3273,19 +3286,53 @@ impl<'hir> GenericArgsCtor<'hir> {
}
}

#[derive(Copy, Clone, Debug)]
enum DirectConstArgContext {
bitflags::bitflags! {
#[derive(Copy, Clone, Debug)]
struct DirectConstArgContext: u16 {
const TUPLE_CALL = 1 << 0;
const TUPLE = 1 << 1;
const PATH_PLAIN_PARAM = 1 << 2;
const PATH_CONST_CTOR = 1 << 3;
const PATH_ANY = 1 << 4;
const STRUCT = 1 << 5;
const ARRAY = 1 << 6;
const UNDERSCORE = 1 << 7;
const PAREN = 1 << 8;
const BLOCK = 1 << 9;
const LIT = 1 << 10;
const CONST_BLOCK = 1 << 11;
const GCA_MACRO = 1 << 12;
}
}

impl DirectConstArgContext {
/// The only allowed direct const arg representation is simple paths that nameres to generic
/// const parameters.
Stable,
const STABLE: DirectConstArgContext = Self::PATH_PLAIN_PARAM;

/// The allowed representations are what is allowed on stable, plus the `gca!` macro.
MinGenericConstArgs,
/// Expressions attempt to be lowered directly, and if that fails, the expression falls back to
/// being represented as an anon const.
const GCA: DirectConstArgContext = Self::STABLE.union(Self::GCA_MACRO);

/// These expressions are allowed inside the `gca!` macro, regardless of what feature is
/// enabling the base `gca!` functionality.
///
/// This context is also used under MinGenericConstArgs inside a `gca!` macro, for
/// simplicity, as they allow the same code.
MacrolessMinGenericConstArgs,
/// These are also allowed under macroless features without a `gca!` macro.
const GCA_BASE_FEATURES: DirectConstArgContext = Self::GCA
.union(DirectConstArgContext::UNDERSCORE)
.union(DirectConstArgContext::PAREN)
.union(DirectConstArgContext::BLOCK)
.union(DirectConstArgContext::LIT)
.union(DirectConstArgContext::CONST_BLOCK);

/// These are allowed under `#![feature(gca_min_const_items)]`
const GCA_MIN_CONST_ITEMS: DirectConstArgContext = DirectConstArgContext::PATH_ANY;

/// These are allowed under `#![feature(gca_adts)]`
const GCA_ADTS: DirectConstArgContext = DirectConstArgContext::PATH_CONST_CTOR
.union(DirectConstArgContext::TUPLE_CALL)
.union(DirectConstArgContext::TUPLE)
.union(DirectConstArgContext::STRUCT)
.union(DirectConstArgContext::ARRAY);
}

#[derive(Debug)]
Expand Down
59 changes: 40 additions & 19 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token
use rustc_attr_ir::{Attribute, AttributeKind};
use rustc_attr_parsing::AttributeParser;
use rustc_errors::msg;
use rustc_feature::Features;
use rustc_feature::{DependentFeature, Features};
use rustc_session::Session;
use rustc_session::diagnostics::{feature_err, feature_warn};
use rustc_span::{Span, Spanned, sym};
Expand Down Expand Up @@ -652,26 +652,47 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
}

fn check_dependent_features(sess: &Session, features: &Features) {
for &(parent, children) in
rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, _)| features.enabled(*parent))
for &(parent, ref children) in
rustc_feature::DEPENDENT_FEATURES.iter().filter(|(parent, children)| {
features.enabled(*parent) && !check_enabled(features, children)
})
{
if children.iter().any(|f| !features.enabled(*f)) {
let parent_span = features
.enabled_features_iter_stable_order()
.find_map(|(name, span)| (name == parent).then_some(span))
.unwrap();
// FIXME: should probably format this in fluent instead of here
let missing = children
let parent_span = features
.enabled_features_iter_stable_order()
.find_map(|(name, span)| (name == parent).then_some(span))
.unwrap();
// FIXME: should probably format this in fluent instead of here
let missing = format(features, &children);
sess.dcx().emit_err(diagnostics::MissingDependentFeatures { parent_span, parent, missing });
}

fn check_enabled(features: &Features, feature: &DependentFeature) -> bool {
match feature {
DependentFeature::And(children) => {
children.iter().all(|child| check_enabled(features, child))
}
DependentFeature::Or(children) => {
children.iter().any(|child| check_enabled(features, child))
}
DependentFeature::Leaf(symbol) => features.enabled(*symbol),
}
}

fn format(features: &Features, feature: &DependentFeature) -> String {
// FIXME: parentheses/precedence
match feature {
DependentFeature::And(children) => children
.iter()
.filter(|f| !features.enabled(**f))
.map(|s| format!("`{}`", s.as_str()))
.intersperse(String::from(", "))
.collect();
sess.dcx().emit_err(diagnostics::MissingDependentFeatures {
parent_span,
parent,
missing,
});
.filter(|child| !check_enabled(features, child))
.map(|child| format(features, child))
.intersperse(String::from(" and "))
.collect(),
DependentFeature::Or(children) => children
.iter()
.map(|child| format(features, child))
.intersperse(String::from(" or "))
.collect(),
DependentFeature::Leaf(symbol) => format!("`{}`", symbol.as_str()),
}
}
}
Expand Down
Loading
Loading