1use std::borrow::Cow;
4use std::num::NonZero;
5use std::ops::Deref;
6use std::{assert_matches, mem};
7
8use rustc_attr_ir::lang_items::LangItem;
9use rustc_attr_ir::{ConstStability, StabilityLevel, find_attr};
10use rustc_errors::{Diag, ErrorGuaranteed};
11use rustc_hir as hir;
12use rustc_hir::def::DefKind;
13use rustc_hir::def_id::DefId;
14use rustc_index::bit_set::DenseBitSet;
15use rustc_infer::infer::TyCtxtInferExt;
16use rustc_middle::mir::visit::Visitor;
17use rustc_middle::mir::*;
18use rustc_middle::ty::adjustment::PointerCoercion;
19use rustc_middle::ty::{self, Ty, TypeVisitableExt};
20use rustc_mir_dataflow::Analysis;
21use rustc_mir_dataflow::impls::{MaybeStorageLive, always_storage_live_locals};
22use rustc_span::{Span, Symbol, span_bug, sym};
23use rustc_trait_selection::traits::{
24 Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
25};
26use tracing::{instrument, trace};
27
28use super::ops::{self, NonConstOp, Status};
29use super::qualifs::{self, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
30use super::resolver::FlowSensitiveAnalysis;
31use super::{ConstCx, Qualif};
32use crate::check_consts::is_fn_or_trait_safe_to_expose_on_stable;
33use crate::diagnostics;
34
35type QualifResults<'mir, 'tcx, Q> =
36 rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'tcx, Q>>;
37
38#[derive(#[automatically_derived]
impl ::core::marker::Copy for ConstConditionsHold { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ConstConditionsHold { }
#[automatically_derived]
impl ::core::clone::Clone for ConstConditionsHold {
#[inline]
fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ConstConditionsHold { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ConstConditionsHold {
#[inline]
fn eq(&self, other: &Self) -> bool {
::core::intrinsics::discriminant_value(self) ==
::core::intrinsics::discriminant_value(other)
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ConstConditionsHold { }Eq, #[automatically_derived]
impl ::core::fmt::Debug for ConstConditionsHold {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ConstConditionsHold::Yes => "Yes",
ConstConditionsHold::No => "No",
})
}
}Debug)]
39enum ConstConditionsHold {
40 Yes,
41 No,
42}
43
44#[derive(#[automatically_derived]
impl<'mir, 'tcx> ::core::default::Default for Qualifs<'mir, 'tcx> {
#[inline]
fn default() -> Self {
Self {
has_mut_interior: ::core::default::Default::default(),
needs_drop: ::core::default::Default::default(),
needs_non_const_drop: ::core::default::Default::default(),
}
}
}Default)]
45pub(crate) struct Qualifs<'mir, 'tcx> {
46 has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
47 needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
48 needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
49}
50
51impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
52 fn in_local<Q: Qualif>(
56 qualif_results: &mut Option<QualifResults<'mir, 'tcx, Q>>,
57 ccx: &'mir ConstCx<'mir, 'tcx>,
58 local: Local,
59 location: Location,
60 ) -> bool {
61 let ty = ccx.body.local_decls[local].ty;
62 if !ty.has_opaque_types() && !Q::in_any_value_of_ty(ccx, ty) {
66 return false;
67 }
68
69 let qualif_results = qualif_results.get_or_insert_with(|| {
70 let ConstCx { tcx, body, .. } = *ccx;
71
72 FlowSensitiveAnalysis::new(ccx)
73 .iterate_to_fixpoint(tcx, body, None)
74 .into_results_cursor(body)
75 });
76
77 qualif_results.seek_before_primary_effect(location);
78 qualif_results.get().contains(local)
79 }
80
81 fn in_return_place(
82 &mut self,
83 ccx: &'mir ConstCx<'mir, 'tcx>,
84 tainted_by_errors: Option<ErrorGuaranteed>,
85 ) -> ConstQualifs {
86 let return_block = ccx
93 .body
94 .basic_blocks
95 .iter_enumerated()
96 .find(|(_, block)| #[allow(non_exhaustive_omitted_patterns)] match block.terminator().kind {
TerminatorKind::Return => true,
_ => false,
}matches!(block.terminator().kind, TerminatorKind::Return))
97 .map(|(bb, _)| bb);
98
99 let Some(return_block) = return_block else {
100 return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
101 };
102
103 let return_loc = ccx.body.terminator_loc(return_block);
104
105 ConstQualifs {
106 needs_drop: Self::in_local(&mut self.needs_drop, ccx, RETURN_PLACE, return_loc),
107 needs_non_const_drop: Self::in_local(
108 &mut self.needs_non_const_drop,
109 ccx,
110 RETURN_PLACE,
111 return_loc,
112 ),
113 has_mut_interior: Self::in_local(
114 &mut self.has_mut_interior,
115 ccx,
116 RETURN_PLACE,
117 return_loc,
118 ),
119 tainted_by_errors,
120 }
121 }
122}
123
124pub struct Checker<'mir, 'tcx> {
125 ccx: &'mir ConstCx<'mir, 'tcx>,
126 qualifs: Qualifs<'mir, 'tcx>,
127
128 span: Span,
130
131 transient_locals: Option<DenseBitSet<Local>>,
134
135 error_emitted: Option<ErrorGuaranteed>,
136 secondary_errors: Vec<Diag<'tcx>>,
137}
138
139impl<'mir, 'tcx> Deref for Checker<'mir, 'tcx> {
140 type Target = ConstCx<'mir, 'tcx>;
141
142 fn deref(&self) -> &Self::Target {
143 self.ccx
144 }
145}
146
147impl<'mir, 'tcx> Checker<'mir, 'tcx> {
148 pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
149 Checker {
150 span: ccx.body.span,
151 ccx,
152 qualifs: Default::default(),
153 transient_locals: None,
154 error_emitted: None,
155 secondary_errors: Vec::new(),
156 }
157 }
158
159 pub fn check_body(&mut self) {
160 let ConstCx { tcx, body, .. } = *self.ccx;
161 let def_id = self.ccx.def_id();
162
163 if self.ccx.is_async() || body.coroutine.is_some() {
166 tcx.dcx().span_delayed_bug(body.span, "`async` functions cannot be `const fn`");
167 return;
168 }
169
170 if !{
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDoNotConstCheck) =>
{
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(tcx, def_id, RustcDoNotConstCheck) {
171 self.visit_body(body);
172 }
173
174 let secondary_errors = mem::take(&mut self.secondary_errors);
177 if self.error_emitted.is_none() {
178 for error in secondary_errors {
179 self.error_emitted = Some(error.emit_err());
180 }
181 } else {
182 if !self.tcx.dcx().has_errors().is_some() {
::core::panicking::panic("assertion failed: self.tcx.dcx().has_errors().is_some()")
};assert!(self.tcx.dcx().has_errors().is_some());
183 for error in secondary_errors {
184 error.cancel();
185 }
186 }
187 }
188
189 fn local_is_transient(&mut self, local: Local) -> bool {
190 let ccx = self.ccx;
191 self.transient_locals
192 .get_or_insert_with(|| {
193 let always_live_locals = &always_storage_live_locals(&ccx.body);
196 let mut maybe_storage_live =
197 MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
198 .iterate_to_fixpoint(ccx.tcx, &ccx.body, None)
199 .into_results_cursor(&ccx.body);
200
201 let mut transient = DenseBitSet::new_filled(ccx.body.local_decls.len());
204 for (bb, data) in traversal::reachable(&ccx.body) {
206 if data.terminator().kind == TerminatorKind::Return {
207 let location = ccx.body.terminator_loc(bb);
208 maybe_storage_live.seek_after_primary_effect(location);
209 transient.subtract(maybe_storage_live.get());
211 }
212 }
213
214 transient
215 })
216 .contains(local)
217 }
218
219 pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
220 self.qualifs.in_return_place(self.ccx, self.error_emitted)
221 }
222
223 pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
225 self.check_op_spanned(op, self.span);
226 }
227
228 pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
231 let gate = match op.status_in_item(self.ccx) {
232 Status::Unstable {
233 gate,
234 safe_to_expose_on_stable,
235 is_function_call,
236 gate_already_checked,
237 } if gate_already_checked || self.tcx.features().enabled(gate) => {
238 if gate_already_checked {
239 if !!safe_to_expose_on_stable {
{
::core::panicking::panic_fmt(format_args!("setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense"));
}
};assert!(
240 !safe_to_expose_on_stable,
241 "setting `gate_already_checked` without `safe_to_expose_on_stable` makes no sense"
242 );
243 }
244 if !safe_to_expose_on_stable
247 && self.enforce_recursive_const_stability()
248 && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate)
249 {
250 let already_unstable = {
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(self.def_id(),
&self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcConstStability {
stability, .. }) if stability.is_const_unstable() => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, self.def_id(), RustcConstStability { stability, .. } if stability.is_const_unstable());
254 emit_unstable_in_stable_exposed_error(
255 self.ccx,
256 span,
257 gate,
258 is_function_call,
259 already_unstable,
260 );
261 }
262
263 return;
264 }
265
266 Status::Unstable { gate, .. } => Some(gate),
267 Status::Forbidden => None,
268 };
269
270 if self.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
271 self.tcx.sess.miri_unleashed_feature(span, gate);
272 return;
273 }
274
275 let err = op.build_error(self.ccx, span);
276 if !err.is_error() {
::core::panicking::panic("assertion failed: err.is_error()")
};assert!(err.is_error());
277
278 match op.importance() {
279 ops::DiagImportance::Primary => {
280 let guar = err.emit_err();
281 self.error_emitted = Some(guar);
282 }
283
284 ops::DiagImportance::Secondary => {
285 self.secondary_errors.push(err);
286 self.tcx.dcx().span_delayed_bug(
287 span,
288 "compilation must fail when there is a secondary const checker error",
289 );
290 }
291 }
292 }
293
294 fn check_static(&mut self, def_id: DefId, span: Span) {
295 if self.tcx.is_thread_local_static(def_id) {
296 self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
297 }
298 if let Some(def_id) = def_id.as_local()
299 && let Err(guar) = self.tcx.ensure_result().check_well_formed(hir::OwnerId { def_id })
300 {
301 self.error_emitted = Some(guar);
302 }
303 }
304
305 fn place_may_escape(&mut self, place: &Place<'_>) -> bool {
309 let is_transient = match self.const_kind() {
310 hir::ConstContext::ConstFn => true,
318 _ => {
319 place.is_indirect() || self.local_is_transient(place.local)
331 }
332 };
333 !is_transient
336 }
337
338 fn revalidate_conditional_constness(
340 &mut self,
341 callee: DefId,
342 callee_args: ty::GenericArgsRef<'tcx>,
343 call_span: Span,
344 ) -> Option<ConstConditionsHold> {
345 let tcx = self.tcx;
346 if !tcx.is_conditionally_const(callee) {
347 return None;
348 }
349
350 let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
351 if const_conditions.is_empty() {
352 return None;
353 }
354
355 let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(self.body.typing_env(tcx));
356 let ocx = ObligationCtxt::new(&infcx);
357
358 let body_id = self.body.source.def_id().expect_local();
359 let host_polarity = match self.const_kind() {
360 hir::ConstContext::ConstFn => ty::BoundConstness::Maybe,
361 hir::ConstContext::Static(_) | hir::ConstContext::Const { .. } => {
362 ty::BoundConstness::Const
363 }
364 };
365 let const_conditions = const_conditions.into_iter().map(|(c, s)| {
366 (ocx.normalize(&ObligationCause::misc(call_span, body_id), param_env, c), s)
367 });
368 ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| {
369 Obligation::new(
370 tcx,
371 ObligationCause::new(
372 call_span,
373 body_id,
374 ObligationCauseCode::WhereClause(callee, span),
375 ),
376 param_env,
377 trait_ref.to_host_effect_clause(tcx, host_polarity),
378 )
379 }));
380
381 let errors = ocx.evaluate_obligations_error_on_ambiguity();
382 if errors.no_errors() {
383 Some(ConstConditionsHold::Yes)
384 } else {
385 tcx.dcx()
386 .span_delayed_bug(call_span, "this should have reported a [const] error in HIR");
387 Some(ConstConditionsHold::No)
388 }
389 }
390
391 pub fn check_drop_terminator(
392 &mut self,
393 dropped_place: Place<'tcx>,
394 location: Location,
395 terminator_span: Span,
396 ) {
397 let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
398
399 let needs_drop = if let Some(local) = dropped_place.as_local() {
400 Qualifs::in_local(&mut self.qualifs.needs_drop, self.ccx, local, location)
401 } else {
402 qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
403 };
404 if !needs_drop {
406 return;
407 }
408
409 let mut err_span = self.span;
410 let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
411 err_span = self.body.local_decls[local].source_info.span;
413 Qualifs::in_local(&mut self.qualifs.needs_non_const_drop, self.ccx, local, location)
414 } else {
415 qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
416 };
417
418 self.check_op_spanned(
419 ops::LiveDrop {
420 dropped_at: terminator_span,
421 dropped_ty: ty_of_dropped_place,
422 needs_non_const_drop,
423 },
424 err_span,
425 );
426 }
427
428 fn check_callee_stability(&mut self, def_id: DefId) {
430 match self.tcx.lookup_const_stability(def_id) {
431 Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
432 }
434 None => {
435 if self.enforce_recursive_const_stability()
439 && !is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id)
440 {
441 self.dcx().emit_err(diagnostics::UnmarkedConstItemExposed {
442 span: self.span,
443 def_path: self.tcx.def_path_str(def_id),
444 });
445 }
446 }
447 Some(ConstStability {
448 level: StabilityLevel::Unstable { implied_by: implied_feature, issue, .. },
449 feature,
450 ..
451 }) => {
452 let callee_safe_to_expose_on_stable =
454 is_fn_or_trait_safe_to_expose_on_stable(self.tcx, def_id);
455
456 if (self.span.allows_unstable(feature)
465 || implied_feature.is_some_and(|f| self.span.allows_unstable(f)))
466 && callee_safe_to_expose_on_stable
467 {
468 return;
469 }
470
471 let feature_enabled = def_id.is_local()
476 || self.tcx.features().enabled(feature)
477 || implied_feature.is_some_and(|f| self.tcx.features().enabled(f))
478 || {
479 feature == sym::rustc_private
491 && issue == NonZero::new(27812)
492 && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked
493 };
494 if !feature_enabled || !callee_safe_to_expose_on_stable {
497 self.check_op(ops::CallUnstable {
498 def_id,
499 feature,
500 feature_enabled,
501 safe_to_expose_on_stable: callee_safe_to_expose_on_stable,
502 is_function_call: self.tcx.def_kind(def_id) != DefKind::Trait,
503 });
504 }
505 }
506 }
507 }
508}
509
510impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
511 fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
512 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs:512",
"rustc_const_eval::check_consts::check",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(512u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_basic_block_data: bb={0:?} is_cleanup={1:?}",
bb, block.is_cleanup) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
513
514 if block.is_cleanup {
522 return;
523 }
524
525 self.super_basic_block_data(bb, block);
526 }
527
528 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
529 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs:529",
"rustc_const_eval::check_consts::check",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(529u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_rvalue: rvalue={0:?} location={1:?}",
rvalue, location) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
530
531 self.super_rvalue(rvalue, location);
532
533 match rvalue {
534 Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
535
536 Rvalue::Use(..)
537 | Rvalue::CopyForDeref(..)
538 | Rvalue::Repeat(..)
539 | Rvalue::Discriminant(..) => {}
540
541 Rvalue::Aggregate(kind, ..) => {
542 if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
543 && let Some(coroutine_kind) = self.tcx.coroutine_kind(*def_id)
544 {
545 self.check_op(ops::Coroutine(coroutine_kind));
546 }
547 }
548
549 Rvalue::Ref(_, BorrowKind::Mut { .. }, place)
550 | Rvalue::RawPtr(RawPtrKind::Mut, place) => {
551 let is_allowed =
556 self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut);
557
558 if !is_allowed && self.place_may_escape(place) {
559 self.check_op(ops::EscapingMutBorrow);
560 }
561 }
562
563 Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake(_), place)
564 | Rvalue::RawPtr(RawPtrKind::Const, place) => {
565 let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
566 self.ccx,
567 &mut |local| {
568 Qualifs::in_local(
569 &mut self.qualifs.has_mut_interior,
570 self.ccx,
571 local,
572 location,
573 )
574 },
575 place.as_ref(),
576 );
577
578 if borrowed_place_has_mut_interior && self.place_may_escape(place) {
579 self.check_op(ops::EscapingCellBorrow);
580 }
581 }
582
583 Rvalue::Reborrow(..) => {
584 }
586
587 Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => {
588 if !place.is_indirect() {
591 self.tcx.dcx().span_delayed_bug(
592 self.body.source_info(location).span,
593 "fake borrows are always indirect",
594 );
595 }
596 }
597
598 Rvalue::Cast(
599 CastKind::IntToInt
600 | CastKind::FloatToInt
601 | CastKind::FloatToFloat
602 | CastKind::IntToFloat
603 | CastKind::PtrToPtr
604 | CastKind::FnPtrToPtr
605 | CastKind::Transmute
606 | CastKind::BoxDerefTransmute
607 | CastKind::PointerCoercion(
608 PointerCoercion::MutToConstPointer
609 | PointerCoercion::ArrayToPointer
610 | PointerCoercion::UnsafeFnPointer
611 | PointerCoercion::ClosureFnPointer(_)
612 | PointerCoercion::ReifyFnPointer(_)
613 | PointerCoercion::Unsize,
614 _,
615 ),
616 _,
617 _,
618 ) => {
619 }
621 Rvalue::Cast(CastKind::PointerExposeProvenance, _, _) => {
623 self.check_op(ops::RawPtrToIntCast);
624 }
625 Rvalue::Cast(CastKind::PointerWithExposedProvenance, _, _) => {
626 }
628 Rvalue::Cast(kind @ CastKind::Subtype, _, _) => {
629 ::rustc_span::macros::bug_impl(Some(self.span),
format_args!("invalid CastKind for this MIR phase: {0:?}", kind),
Location::caller());span_bug!(self.span, "invalid CastKind for this MIR phase: {kind:?}");
630 }
631
632 Rvalue::UnaryOp(op, operand) => {
633 let ty = operand.ty(self.body, self.tcx);
634 match op {
635 UnOp::Not | UnOp::Neg => {
636 if is_int_bool_float_or_char(ty) {
637 } else {
639 ::rustc_span::macros::bug_impl(Some(self.span),
format_args!("non-primitive type in `Rvalue::UnaryOp{0:?}`: {1:?}", op,
ty), Location::caller());span_bug!(
640 self.span,
641 "non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}",
642 );
643 }
644 }
645 UnOp::PtrMetadata => {
646 }
649 }
650 }
651
652 Rvalue::BinaryOp(op, (lhs, rhs)) => {
653 let lhs_ty = lhs.ty(self.body, self.tcx);
654 let rhs_ty = rhs.ty(self.body, self.tcx);
655
656 if is_int_bool_float_or_char(lhs_ty) && is_int_bool_float_or_char(rhs_ty) {
657 } else if lhs_ty.is_fn_ptr() || lhs_ty.is_raw_ptr() {
659 {
match op {
BinOp::Eq | BinOp::Ne | BinOp::Le | BinOp::Lt | BinOp::Ge | BinOp::Gt
| BinOp::Offset => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"BinOp::Eq | BinOp::Ne | BinOp::Le | BinOp::Lt | BinOp::Ge | BinOp::Gt |\nBinOp::Offset",
::core::option::Option::None);
}
}
};assert_matches!(
660 op,
661 BinOp::Eq
662 | BinOp::Ne
663 | BinOp::Le
664 | BinOp::Lt
665 | BinOp::Ge
666 | BinOp::Gt
667 | BinOp::Offset
668 );
669
670 self.check_op(ops::RawPtrComparison);
671 } else {
672 ::rustc_span::macros::bug_impl(Some(self.span),
format_args!("non-primitive type in `Rvalue::BinaryOp`: {0:?} ⚬ {1:?}",
lhs_ty, rhs_ty), Location::caller());span_bug!(
673 self.span,
674 "non-primitive type in `Rvalue::BinaryOp`: {:?} ⚬ {:?}",
675 lhs_ty,
676 rhs_ty
677 );
678 }
679 }
680
681 Rvalue::WrapUnsafeBinder(..) => {
682 }
684 }
685 }
686
687 fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
688 self.super_operand(op, location);
689 if let Operand::Constant(c) = op
690 && let Some(def_id) = c.check_static_ptr(self.tcx)
691 {
692 self.check_static(def_id, self.span);
693 }
694 }
695
696 fn visit_source_info(&mut self, source_info: &SourceInfo) {
697 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs:697",
"rustc_const_eval::check_consts::check",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(697u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_source_info: source_info={0:?}",
source_info) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("visit_source_info: source_info={:?}", source_info);
698 self.span = source_info.span;
699 }
700
701 fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
702 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs:702",
"rustc_const_eval::check_consts::check",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(702u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("visit_statement: statement={0:?} location={1:?}",
statement, location) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("visit_statement: statement={:?} location={:?}", statement, location);
703
704 self.super_statement(statement, location);
705
706 match statement.kind {
707 StatementKind::Assign(..)
708 | StatementKind::SetDiscriminant { .. }
709 | StatementKind::FakeRead(..)
710 | StatementKind::StorageLive(_)
711 | StatementKind::StorageDead(_)
712 | StatementKind::PlaceMention(..)
713 | StatementKind::AscribeUserType(..)
714 | StatementKind::Coverage(..)
715 | StatementKind::Intrinsic(..)
716 | StatementKind::ConstEvalCounter
717 | StatementKind::BackwardIncompatibleDropHint { .. }
718 | StatementKind::Nop => {}
719 }
720 }
721
722 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("visit_terminator",
"rustc_const_eval::check_consts::check",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(722u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("terminator")
}> =
::tracing::__macro_support::FieldName::new("terminator");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("location")
}> =
::tracing::__macro_support::FieldName::new("location");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&terminator)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&location)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
self.super_terminator(terminator, location);
match &terminator.kind {
TerminatorKind::Call { func, args, fn_span, .. } |
TerminatorKind::TailCall { func, args, fn_span, .. } => {
let call_source =
match terminator.kind {
TerminatorKind::Call { call_source, .. } => call_source,
TerminatorKind::TailCall { .. } => CallSource::Normal,
_ =>
::core::panicking::panic("internal error: entered unreachable code"),
};
let ConstCx { tcx, body, .. } = *self.ccx;
let fn_ty = func.ty(body, tcx);
let (callee, fn_args) =
match *fn_ty.kind() {
ty::FnDef(def_id, fn_args) =>
(def_id, fn_args.no_bound_vars().unwrap()),
ty::FnPtr(..) => {
self.check_op(ops::FnCallIndirect);
return;
}
_ => {
::rustc_span::macros::bug_impl(Some(terminator.source_info.span),
format_args!("invalid callee of type {0:?}", fn_ty),
Location::caller())
}
};
let has_const_conditions =
self.revalidate_conditional_constness(callee, fn_args,
*fn_span);
if let Some(trait_did) = tcx.trait_of_assoc(callee) {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs:761",
"rustc_const_eval::check_consts::check",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/d080e7dff1b0fc54541545252818f8cccf995d05/compiler/rustc_const_eval/src/check_consts/check.rs"),
::tracing_core::__macro_support::Option::Some(761u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::check"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("attempting to call a trait method")
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
let is_const =
#[allow(non_exhaustive_omitted_patterns)] match tcx.constness(callee)
{
hir::Constness::Const { always: false } => true,
_ => false,
};
if is_const &&
has_const_conditions == Some(ConstConditionsHold::Yes) {
self.check_op(ops::ConditionallyConstCall {
callee,
args: fn_args,
span: *fn_span,
call_source,
});
self.check_callee_stability(trait_did);
} else {
self.check_op(ops::FnCallNonConst {
callee,
args: fn_args,
span: *fn_span,
call_source,
});
}
return;
}
if has_const_conditions.is_some() {
self.check_op(ops::ConditionallyConstCall {
callee,
args: fn_args,
span: *fn_span,
call_source,
});
}
if self.tcx.fn_sig(callee).skip_binder().c_variadic() {
self.check_op(ops::FnCallCVariadic)
}
if tcx.is_lang_item(callee, LangItem::BeginPanic) {
match args[0].node.ty(&self.ccx.body.local_decls,
tcx).kind() {
ty::Ref(_, ty, _) if ty.is_str() => {}
_ => self.check_op(ops::PanicNonStr),
}
return;
}
if tcx.is_lang_item(callee, LangItem::PanicDisplay) {
if let ty::Ref(_, ty, _) =
args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() &&
let ty::Ref(_, ty, _) = ty.kind() && ty.is_str()
{} else { self.check_op(ops::PanicNonStr); }
return;
}
if let Some(intrinsic) = tcx.intrinsic(callee) {
if !tcx.is_const_fn(callee) {
self.check_op(ops::IntrinsicNonConst {
name: intrinsic.name,
});
return;
}
let usable_fallback_body =
!intrinsic.must_be_overridden &&
!{
{
'done:
{
for i in
::rustc_attr_ir::HasAttrs::get_attrs(callee, &self.tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDoNotConstCheck) =>
{
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some();
let const_stable_indirect =
is_fn_or_trait_safe_to_expose_on_stable(tcx, callee) &&
(usable_fallback_body || intrinsic.const_stable_indirect);
match tcx.lookup_const_stability(callee) {
None => {
if !const_stable_indirect &&
self.enforce_recursive_const_stability() {
self.dcx().emit_err(diagnostics::UnmarkedIntrinsicExposed {
span: self.span,
def_path: self.tcx.def_path_str(callee),
});
}
}
Some(ConstStability {
level: StabilityLevel::Unstable { .. }, feature, .. }) => {
if self.span.allows_unstable(feature) &&
const_stable_indirect {
return;
}
self.check_op(ops::IntrinsicUnstable {
name: intrinsic.name,
feature,
const_stable_indirect,
});
}
Some(ConstStability { level: StabilityLevel::Stable { .. },
.. }) => {}
}
return;
}
if !tcx.is_const_fn(callee) {
self.check_op(ops::FnCallNonConst {
callee,
args: fn_args,
span: *fn_span,
call_source,
});
return;
}
self.check_callee_stability(callee);
}
TerminatorKind::Drop { place: dropped_place, .. } => {
if super::post_drop_elaboration::checking_enabled(self.ccx)
{
return;
}
self.check_drop_terminator(*dropped_place, location,
terminator.source_info.span);
}
TerminatorKind::InlineAsm { .. } =>
self.check_op(ops::InlineAsm),
TerminatorKind::Yield { .. } => {
self.check_op(ops::Coroutine(self.tcx.coroutine_kind(self.body.source.def_id()).expect("Only expected to have a yield in a coroutine")));
}
TerminatorKind::CoroutineDrop => {
::rustc_span::macros::bug_impl(Some(self.body.source_info(location).span),
format_args!("We should not encounter TerminatorKind::CoroutineDrop after coroutine transform"),
Location::caller());
}
TerminatorKind::UnwindTerminate(_) => {
::rustc_span::macros::bug_impl(Some(self.span),
format_args!("`Terminate` terminator outside of cleanup block"),
Location::caller())
}
TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { ..
} | TerminatorKind::FalseUnwind { .. } |
TerminatorKind::Goto { .. } | TerminatorKind::UnwindResume |
TerminatorKind::Return | TerminatorKind::SwitchInt { .. } |
TerminatorKind::Unreachable => {}
}
}
}
}#[instrument(level = "debug", skip(self))]
723 fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
724 self.super_terminator(terminator, location);
725
726 match &terminator.kind {
727 TerminatorKind::Call { func, args, fn_span, .. }
728 | TerminatorKind::TailCall { func, args, fn_span, .. } => {
729 let call_source = match terminator.kind {
730 TerminatorKind::Call { call_source, .. } => call_source,
731 TerminatorKind::TailCall { .. } => CallSource::Normal,
732 _ => unreachable!(),
733 };
734
735 let ConstCx { tcx, body, .. } = *self.ccx;
736
737 let fn_ty = func.ty(body, tcx);
738
739 let (callee, fn_args) = match *fn_ty.kind() {
740 ty::FnDef(def_id, fn_args) => (def_id, fn_args.no_bound_vars().unwrap()),
741
742 ty::FnPtr(..) => {
743 self.check_op(ops::FnCallIndirect);
744 return;
747 }
748 _ => {
749 span_bug!(terminator.source_info.span, "invalid callee of type {:?}", fn_ty)
750 }
751 };
752
753 let has_const_conditions =
754 self.revalidate_conditional_constness(callee, fn_args, *fn_span);
755
756 if let Some(trait_did) = tcx.trait_of_assoc(callee) {
758 trace!("attempting to call a trait method");
762 let is_const =
763 matches!(tcx.constness(callee), hir::Constness::Const { always: false });
764
765 if is_const && has_const_conditions == Some(ConstConditionsHold::Yes) {
769 self.check_op(ops::ConditionallyConstCall {
771 callee,
772 args: fn_args,
773 span: *fn_span,
774 call_source,
775 });
776 self.check_callee_stability(trait_did);
777 } else {
778 self.check_op(ops::FnCallNonConst {
780 callee,
781 args: fn_args,
782 span: *fn_span,
783 call_source,
784 });
785 }
786 return;
788 }
789
790 if has_const_conditions.is_some() {
792 self.check_op(ops::ConditionallyConstCall {
793 callee,
794 args: fn_args,
795 span: *fn_span,
796 call_source,
797 });
798 }
799
800 if self.tcx.fn_sig(callee).skip_binder().c_variadic() {
801 self.check_op(ops::FnCallCVariadic)
802 }
803
804 if tcx.is_lang_item(callee, LangItem::BeginPanic) {
812 match args[0].node.ty(&self.ccx.body.local_decls, tcx).kind() {
813 ty::Ref(_, ty, _) if ty.is_str() => {}
814 _ => self.check_op(ops::PanicNonStr),
815 }
816 return;
818 }
819
820 if tcx.is_lang_item(callee, LangItem::PanicDisplay) {
822 if let ty::Ref(_, ty, _) =
823 args[0].node.ty(&self.ccx.body.local_decls, tcx).kind()
824 && let ty::Ref(_, ty, _) = ty.kind()
825 && ty.is_str()
826 {
827 } else {
828 self.check_op(ops::PanicNonStr);
829 }
830 return;
832 }
833
834 if let Some(intrinsic) = tcx.intrinsic(callee) {
836 if !tcx.is_const_fn(callee) {
837 self.check_op(ops::IntrinsicNonConst { name: intrinsic.name });
839 return;
842 }
843 let usable_fallback_body = !intrinsic.must_be_overridden
846 && !find_attr!(self.tcx, callee, RustcDoNotConstCheck);
847 let const_stable_indirect =
848 is_fn_or_trait_safe_to_expose_on_stable(tcx, callee)
849 && (usable_fallback_body || intrinsic.const_stable_indirect);
850 match tcx.lookup_const_stability(callee) {
851 None => {
852 if !const_stable_indirect && self.enforce_recursive_const_stability() {
856 self.dcx().emit_err(diagnostics::UnmarkedIntrinsicExposed {
857 span: self.span,
858 def_path: self.tcx.def_path_str(callee),
859 });
860 }
861 }
862 Some(ConstStability {
863 level: StabilityLevel::Unstable { .. },
864 feature,
865 ..
866 }) => {
867 if self.span.allows_unstable(feature) && const_stable_indirect {
873 return;
874 }
875
876 self.check_op(ops::IntrinsicUnstable {
877 name: intrinsic.name,
878 feature,
879 const_stable_indirect,
880 });
881 }
882 Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => {
883 }
888 }
889 return;
891 }
892
893 if !tcx.is_const_fn(callee) {
894 self.check_op(ops::FnCallNonConst {
895 callee,
896 args: fn_args,
897 span: *fn_span,
898 call_source,
899 });
900 return;
903 }
904
905 self.check_callee_stability(callee);
907 }
908
909 TerminatorKind::Drop { place: dropped_place, .. } => {
912 if super::post_drop_elaboration::checking_enabled(self.ccx) {
915 return;
916 }
917
918 self.check_drop_terminator(*dropped_place, location, terminator.source_info.span);
919 }
920
921 TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),
922
923 TerminatorKind::Yield { .. } => {
924 self.check_op(ops::Coroutine(
925 self.tcx
926 .coroutine_kind(self.body.source.def_id())
927 .expect("Only expected to have a yield in a coroutine"),
928 ));
929 }
930
931 TerminatorKind::CoroutineDrop => {
932 span_bug!(
933 self.body.source_info(location).span,
934 "We should not encounter TerminatorKind::CoroutineDrop after coroutine transform"
935 );
936 }
937
938 TerminatorKind::UnwindTerminate(_) => {
939 span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
941 }
942
943 TerminatorKind::Assert { .. }
944 | TerminatorKind::FalseEdge { .. }
945 | TerminatorKind::FalseUnwind { .. }
946 | TerminatorKind::Goto { .. }
947 | TerminatorKind::UnwindResume
948 | TerminatorKind::Return
949 | TerminatorKind::SwitchInt { .. }
950 | TerminatorKind::Unreachable => {}
951 }
952 }
953}
954
955fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool {
956 ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
957}
958
959fn emit_unstable_in_stable_exposed_error(
960 ccx: &ConstCx<'_, '_>,
961 span: Span,
962 gate: Symbol,
963 is_function_call: bool,
964 already_unstable: bool,
965) -> ErrorGuaranteed {
966 let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
967
968 ccx.dcx().emit_err(diagnostics::UnstableInStableExposed {
969 gate: gate.to_string(),
970 span,
971 suggest_const_unstable: (!already_unstable).then_some(attr_span),
972 is_function_call,
973 is_function_call2: is_function_call,
974 })
975}