Skip to content

Commit

Permalink
Prevent promotion of const fn calls in inline consts
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Sep 18, 2023
1 parent 52f8338 commit 76a4499
Show file tree
Hide file tree
Showing 13 changed files with 37 additions and 20 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
}
}

BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
if self.mir_def.to_def_id() == typeck_root_def_id {
let args =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
false
}

hir::ConstContext::Const | hir::ConstContext::Static(_) => {
hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
.into_engine(ccx.tcx, &ccx.body)
.iterate_to_fixpoint()
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> {
// Everywhere else, we require `#[rustc_promotable]` on the callee.
let promote_all_const_fn = matches!(
self.const_kind,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
);
if !promote_all_const_fn {
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/diagnostic_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext {
DiagnosticArgValue::Str(Cow::Borrowed(match self {
hir::ConstContext::ConstFn => "const_fn",
hir::ConstContext::Static(_) => "static",
hir::ConstContext::Const => "const",
hir::ConstContext::Const { .. } => "const",
}))
}
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ pub enum BodyOwnerKind {
Closure,

/// Constants and associated constants.
Const,
Const { inline: bool },

/// Initializer of a `static` item.
Static(Mutability),
Expand All @@ -1592,7 +1592,7 @@ impl BodyOwnerKind {
pub fn is_fn_or_closure(self) -> bool {
match self {
BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false,
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
}
}
}
Expand All @@ -1615,7 +1615,7 @@ pub enum ConstContext {
///
/// For the most part, other contexts are treated just like a regular `const`, so they are
/// lumped into the same category.
Const,
Const { inline: bool },
}

impl ConstContext {
Expand All @@ -1624,7 +1624,7 @@ impl ConstContext {
/// E.g. `const` or `static mut`.
pub fn keyword_name(self) -> &'static str {
match self {
Self::Const => "const",
Self::Const { .. } => "const",
Self::Static(Mutability::Not) => "static",
Self::Static(Mutability::Mut) => "static mut",
Self::ConstFn => "const fn",
Expand All @@ -1637,7 +1637,7 @@ impl ConstContext {
impl fmt::Display for ConstContext {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Const => write!(f, "constant"),
Self::Const { .. } => write!(f, "constant"),
Self::Static(_) => write!(f, "static"),
Self::ConstFn => write!(f, "constant function"),
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let effect = match const_context {
_ if host_always_on => tcx.consts.true_,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
tcx.consts.false_
}
Some(hir::ConstContext::ConstFn) => {
let args = ty::GenericArgs::identity_for_item(tcx, context);
args.host_effect_param().expect("ConstContext::Maybe must have host effect param")
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Type only exists for constants and statics, not functions.
match self.tcx.hir().body_owner_kind(item_def_id) {
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id);
wbcx.visit_node_id(body.value.span, item_hir_id);
}
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,9 +442,10 @@ impl<'hir> Map<'hir> {
/// Panics if `LocalDefId` does not have an associated body.
pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
match self.tcx.def_kind(def_id) {
DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
BodyOwnerKind::Const
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
BodyOwnerKind::Const { inline: false }
}
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
Expand All @@ -461,7 +462,7 @@ impl<'hir> Map<'hir> {
/// just that it has to be checked as if it were.
pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
let ccx = match self.body_owner_kind(def_id) {
BodyOwnerKind::Const => ConstContext::Const,
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),

BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
_ => bug!("expected closure or generator, found {ty:?}"),
}
}
hir::BodyOwnerKind::Const => 0,
hir::BodyOwnerKind::Const { .. } => 0,
hir::BodyOwnerKind::Static(_) => 0,
};
let mut cfg = CFG { basic_blocks: IndexVec::new() };
Expand Down Expand Up @@ -701,7 +701,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Constants always need overflow checks.
check_overflow |= matches!(
tcx.hir().body_owner_kind(def),
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
);

let lint_level = LintLevel::Explicit(hir_id);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
let body = match tcx.hir().body_const_context(def) {
// consts and statics do not have `optimized_mir`, so we can steal the body instead of
// cloning it.
Some(hir::ConstContext::Const | hir::ConstContext::Static(_)) => body.steal(),
Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(),
Some(hir::ConstContext::ConstFn) => body.borrow().clone(),
None => bug!("`mir_for_ctfe` called on non-const {def:?}"),
};
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_passes/src/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,12 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
}

fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
let kind = Some(hir::ConstContext::Const);
let kind = Some(hir::ConstContext::Const { inline: false });
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
}

fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
let kind = Some(hir::ConstContext::Const);
let kind = Some(hir::ConstContext::Const { inline: true });
self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/inline-const/promotion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#![feature(inline_const)]
#![allow(arithmetic_overflow, unconditional_panic)]
// check-pass

// The only way to have promoteds that fail is in `const fn` called from `const`/`static`.
const fn div_by_zero() -> i32 {
Expand All @@ -15,6 +14,7 @@ fn main() {
let v = const {
if mk_false() {
let _x: &'static i32 = &div_by_zero();
//~^ ERROR: temporary value dropped while borrowed
}
42
};
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/inline-const/promotion.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/promotion.rs:16:37
|
LL | let _x: &'static i32 = &div_by_zero();
| ------------ ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
LL |
LL | }
| - temporary value is freed at the end of this statement

error: aborting due to previous error

For more information about this error, try `rustc --explain E0716`.

0 comments on commit 76a4499

Please sign in to comment.