Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ jobs:
df -h
- name: upload artifacts to github
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
# name is set in previous step
name: ${{ env.DOC_ARTIFACT_NAME }}
Expand Down
27 changes: 13 additions & 14 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2844,10 +2844,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
None,
);

let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = self.lower_expr_to_const_arg_direct(arg, None);
&*self.arena.alloc(const_arg)
}));
let lowered_args = self.arena.alloc_from_iter(
args.iter().map(|arg| self.lower_expr_to_const_arg_direct(arg, None)),
);

ConstArg {
hir_id: self.lower_node_id(node_id),
Expand All @@ -2856,10 +2855,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
let expr = self.lower_expr_to_const_arg_direct(expr, None);
&*self.arena.alloc(expr)
}));
let exprs = self.arena.alloc_from_iter(
exprs.iter().map(|expr| self.lower_expr_to_const_arg_direct(expr, None)),
);

ConstArg {
hir_id: self.lower_node_id(node_id),
Expand Down Expand Up @@ -2892,12 +2890,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
let expr = self.lower_expr_to_const_arg_direct(&f.expr, None);

&*self.arena.alloc(hir::ConstArgExprField {
hir::ConstArgExprField {
hir_id,
field: self.lower_ident(f.ident),
expr: self.arena.alloc(expr),
span: self.lower_span(f.span),
})
}
}));

ConstArg {
Expand All @@ -2907,10 +2905,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
ExprKind::Array(elements) => {
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
let const_arg = self.lower_expr_to_const_arg_direct(element, None);
&*self.arena.alloc(const_arg)
}));
let lowered_elems = self.arena.alloc_from_iter(
elements
.iter()
.map(|element| self.lower_expr_to_const_arg_direct(element, None)),
);
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
span: self.lower_span(expr.span),
elems: lowered_elems,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ pub fn in_any_value_of_ty<'tcx>(
/// To accomplish this, const-checking and promotion use a value-based analysis (as opposed to a
/// type-based one). Qualifications propagate structurally across variables: If a local (or a
/// projection of a local) is assigned a qualified value, that local itself becomes qualified.
///
/// Note that whenever this analysis relies on something being UB and hence impossible in
/// well-defined code, it is crucial that const-eval actually detects that UB! Const-eval is not
/// guaranteed to detect all UB, and if it would skip this particular UB we may end up executing
/// code that has not been const-checked.
pub trait Qualif {
/// The name of the file used to debug the dataflow analysis that computes this qualif.
const ANALYSIS_NAME: &'static str;
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_const_eval/src/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@ where

/// `&` only allow mutation if the borrowed place is `!Freeze`.
///
/// This assumes that it is UB to take the address of a struct field whose type is
/// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
/// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
/// have to check the type of the borrowed **local** instead of the borrowed **place**
/// below. See [rust-lang/unsafe-code-guidelines#134].
///
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
/// This assumes that const-eval will abort when one creates a shared reference to a struct
/// field whose type is `Freeze`, then uses pointer arithmetic to derive a pointer to a
/// *different* field of that same struct whose type is `!Freeze` and mutates that. It is not
/// enough for that to be UB (which we are pretty sure it is, and it would be a breaking change
/// to make it non-UB as we'd then have to make const checking more conservative here),
/// const-eval also has to reliably detect that UB to ensure we never invoke a destructor after
/// such a mutation occurs!
fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
!place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.typing_env)
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
return interp_ok(None);
}
// If it's a frozen shared reference that's not already immutable, potentially make it immutable.
// (Do nothing on `None` provenance, that cannot store immutability anyway.)
// (Do nothing on `None` provenance, that cannot be used to perform mutation anyway.)
// Note that const-checking relies on the UB detection we are implementing here! Specifically,
// the analysis for which destructors may be invoked relies on `&impl Freeze` references not
// being able to change what gets dropped.
if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind()
&& *mutbl == Mutability::Not
&& val.to_scalar_and_meta().0.to_pointer(ecx).provenance.is_some_and(|p| !p.immutable())
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> {
#[derive(Clone, Copy, Debug, StableHash)]
#[repr(u8, C)]
pub enum ConstArgKind<'hir, Unambig = ()> {
Tup(&'hir [&'hir ConstArg<'hir>]),
Tup(&'hir [ConstArg<'hir>]),
/// **Note:** Currently this is only used for bare const params
/// (`N` where `fn foo<const N: usize>(...)`),
/// not paths to any const (`N` where `const N: usize = ...`).
Expand All @@ -517,9 +517,9 @@ pub enum ConstArgKind<'hir, Unambig = ()> {
Path(QPath<'hir>),
Anon(&'hir AnonConst),
/// Represents construction of struct/struct variants
Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]),
Struct(QPath<'hir>, &'hir [ConstArgExprField<'hir>]),
/// Tuple constructor variant
TupleCall(QPath<'hir>, &'hir [&'hir ConstArg<'hir>]),
TupleCall(QPath<'hir>, &'hir [ConstArg<'hir>]),
/// Array literal argument
Array(&'hir ConstArgArrayExpr<'hir>),
/// Error const
Expand All @@ -544,7 +544,7 @@ pub struct ConstArgExprField<'hir> {
#[derive(Clone, Copy, Debug, StableHash)]
pub struct ConstArgArrayExpr<'hir> {
pub span: Span,
pub elems: &'hir [&'hir ConstArg<'hir>],
pub elems: &'hir [ConstArg<'hir>],
}

/// Tracks what a [GenericArg::Infer] can be inferred to based on its syntax.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,13 +1129,13 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
ConstArgKind::TupleCall(qpath, args) => {
try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span()));
for arg in *args {
try_visit!(visitor.visit_const_arg_unambig(*arg));
try_visit!(visitor.visit_const_arg_unambig(arg));
}
V::Result::output()
}
ConstArgKind::Array(array_expr) => {
for arg in array_expr.elems {
try_visit!(visitor.visit_const_arg_unambig(*arg));
try_visit!(visitor.visit_const_arg_unambig(arg));
}
V::Result::output()
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2541,7 +2541,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
hir_id: HirId,
qpath: hir::QPath<'_>,
args: &[&hir::ConstArg<'_>],
args: &[hir::ConstArg<'_>],
span: Span,
) -> Const<'tcx> {
let tcx = self.tcx();
Expand Down Expand Up @@ -2642,7 +2642,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

fn lower_const_arg_tup(
&self,
exprs: &[&hir::ConstArg<'_>],
exprs: &[hir::ConstArg<'_>],
ty: Ty<'tcx>,
span: Span,
) -> Const<'tcx> {
Expand Down Expand Up @@ -2685,7 +2685,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self,
hir_id: HirId,
qpath: hir::QPath<'_>,
inits: &[&hir::ConstArgExprField<'_>],
inits: &[hir::ConstArgExprField<'_>],
span: Span,
) -> Const<'tcx> {
// FIXME(mgca): try to deduplicate this function with
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,14 +1216,14 @@ impl<'a> State<'a> {
}
}

fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &&[&ConstArgExprField<'_>]) {
fn print_const_struct(&mut self, qpath: &hir::QPath<'_>, fields: &[ConstArgExprField<'_>]) {
self.print_qpath(qpath, true);
self.word(" ");
self.word("{");
if !fields.is_empty() {
self.nbsp();
}
self.commasep(Inconsistent, *fields, |s, field| {
self.commasep(Inconsistent, fields, |s, field| {
s.word(field.field.as_str().to_string());
s.word(":");
s.nbsp();
Expand All @@ -1232,10 +1232,10 @@ impl<'a> State<'a> {
self.word("}");
}

fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &&[&ConstArg<'_, ()>]) {
fn print_const_ctor(&mut self, qpath: &hir::QPath<'_>, args: &[ConstArg<'_, ()>]) {
self.print_qpath(qpath, true);
self.word("(");
self.commasep(Inconsistent, *args, |s, arg| {
self.commasep(Inconsistent, args, |s, arg| {
s.print_const_arg(arg);
});
self.word(")");
Expand Down
Loading
Loading