1 //! Concrete error types for all operations which may be invalid in a certain const context. 2 3 use hir::def_id::LocalDefId; 4 use hir::{ConstContext, LangItem}; 5 use rustc_errors::{error_code, DiagnosticBuilder, ErrorGuaranteed}; 6 use rustc_hir as hir; 7 use rustc_hir::def_id::DefId; 8 use rustc_infer::infer::TyCtxtInferExt; 9 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; 10 use rustc_middle::mir::{self, CallSource}; 11 use rustc_middle::ty::print::with_no_trimmed_paths; 12 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; 13 use rustc_middle::ty::TraitRef; 14 use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; 15 use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind}; 16 use rustc_session::parse::feature_err; 17 use rustc_span::symbol::sym; 18 use rustc_span::{BytePos, Pos, Span, Symbol}; 19 use rustc_trait_selection::traits::SelectionContext; 20 21 use super::ConstCx; 22 use crate::errors; 23 24 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 25 pub enum Status { 26 Allowed, 27 Unstable(Symbol), 28 Forbidden, 29 } 30 31 #[derive(Clone, Copy)] 32 pub enum DiagnosticImportance { 33 /// An operation that must be removed for const-checking to pass. 34 Primary, 35 36 /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere. 37 Secondary, 38 } 39 40 /// An operation that is not *always* allowed in a const context. 41 pub trait NonConstOp<'tcx>: std::fmt::Debug { 42 /// Returns an enum indicating whether this operation is allowed within the given item. status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status43 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { 44 Status::Forbidden 45 } 46 importance(&self) -> DiagnosticImportance47 fn importance(&self) -> DiagnosticImportance { 48 DiagnosticImportance::Primary 49 } 50 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>51 fn build_error( 52 &self, 53 ccx: &ConstCx<'_, 'tcx>, 54 span: Span, 55 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; 56 } 57 58 #[derive(Debug)] 59 pub struct FloatingPointOp; 60 impl<'tcx> NonConstOp<'tcx> for FloatingPointOp { status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status61 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { 62 if ccx.const_kind() == hir::ConstContext::ConstFn { 63 Status::Unstable(sym::const_fn_floating_point_arithmetic) 64 } else { 65 Status::Allowed 66 } 67 } 68 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>69 fn build_error( 70 &self, 71 ccx: &ConstCx<'_, 'tcx>, 72 span: Span, 73 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 74 feature_err( 75 &ccx.tcx.sess.parse_sess, 76 sym::const_fn_floating_point_arithmetic, 77 span, 78 format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()), 79 ) 80 } 81 } 82 83 /// A function call where the callee is a pointer. 84 #[derive(Debug)] 85 pub struct FnCallIndirect; 86 impl<'tcx> NonConstOp<'tcx> for FnCallIndirect { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>87 fn build_error( 88 &self, 89 ccx: &ConstCx<'_, 'tcx>, 90 span: Span, 91 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 92 ccx.tcx.sess.create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() }) 93 } 94 } 95 96 /// A function call where the callee is not marked as `const`. 97 #[derive(Debug, Clone, Copy)] 98 pub struct FnCallNonConst<'tcx> { 99 pub caller: LocalDefId, 100 pub callee: DefId, 101 pub substs: SubstsRef<'tcx>, 102 pub span: Span, 103 pub call_source: CallSource, 104 pub feature: Option<Symbol>, 105 } 106 107 impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { build_error( &self, ccx: &ConstCx<'_, 'tcx>, _: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>108 fn build_error( 109 &self, 110 ccx: &ConstCx<'_, 'tcx>, 111 _: Span, 112 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 113 let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self; 114 let ConstCx { tcx, param_env, .. } = *ccx; 115 116 let diag_trait = |err, self_ty: Ty<'_>, trait_id| { 117 let trait_ref = TraitRef::from_method(tcx, trait_id, substs); 118 119 match self_ty.kind() { 120 Param(param_ty) => { 121 debug!(?param_ty); 122 let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller); 123 if let Some(generics) = tcx.hir().get(caller_hir_id).generics() { 124 let constraint = with_no_trimmed_paths!(format!( 125 "~const {}", 126 trait_ref.print_only_trait_path() 127 )); 128 suggest_constraining_type_param( 129 tcx, 130 generics, 131 err, 132 ¶m_ty.name.as_str(), 133 &constraint, 134 None, 135 None, 136 ); 137 } 138 } 139 Adt(..) => { 140 let obligation = 141 Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); 142 143 let infcx = tcx.infer_ctxt().build(); 144 let mut selcx = SelectionContext::new(&infcx); 145 let implsrc = selcx.select(&obligation); 146 147 if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { 148 let span = tcx.def_span(data.impl_def_id); 149 err.subdiagnostic(errors::NonConstImplNote { span }); 150 } 151 } 152 _ => {} 153 } 154 }; 155 156 let call_kind = 157 call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None); 158 159 debug!(?call_kind); 160 161 let mut err = match call_kind { 162 CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => { 163 macro_rules! error { 164 ($err:ident) => { 165 tcx.sess.create_err(errors::$err { 166 span, 167 ty: self_ty, 168 kind: ccx.const_kind(), 169 }) 170 }; 171 } 172 173 let mut err = match kind { 174 CallDesugaringKind::ForLoopIntoIter => { 175 error!(NonConstForLoopIntoIter) 176 } 177 CallDesugaringKind::QuestionBranch => { 178 error!(NonConstQuestionBranch) 179 } 180 CallDesugaringKind::QuestionFromResidual => { 181 error!(NonConstQuestionFromResidual) 182 } 183 CallDesugaringKind::TryBlockFromOutput => { 184 error!(NonConstTryBlockFromOutput) 185 } 186 CallDesugaringKind::Await => { 187 error!(NonConstAwait) 188 } 189 }; 190 191 diag_trait(&mut err, self_ty, kind.trait_def_id(tcx)); 192 err 193 } 194 CallKind::FnCall { fn_trait_id, self_ty } => { 195 let note = match self_ty.kind() { 196 FnDef(def_id, ..) => { 197 let span = tcx.def_span(*def_id); 198 if ccx.tcx.is_const_fn_raw(*def_id) { 199 span_bug!(span, "calling const FnDef errored when it shouldn't"); 200 } 201 202 Some(errors::NonConstClosureNote::FnDef { span }) 203 } 204 FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr), 205 Closure(..) => Some(errors::NonConstClosureNote::Closure), 206 _ => None, 207 }; 208 209 let mut err = tcx.sess.create_err(errors::NonConstClosure { 210 span, 211 kind: ccx.const_kind(), 212 note, 213 }); 214 215 diag_trait(&mut err, self_ty, fn_trait_id); 216 err 217 } 218 CallKind::Operator { trait_id, self_ty, .. } => { 219 let mut err = if let CallSource::MatchCmp = call_source { 220 tcx.sess.create_err(errors::NonConstMatchEq { 221 span, 222 kind: ccx.const_kind(), 223 ty: self_ty, 224 }) 225 } else { 226 let mut sugg = None; 227 228 if Some(trait_id) == ccx.tcx.lang_items().eq_trait() { 229 match (substs[0].unpack(), substs[1].unpack()) { 230 (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty)) 231 if self_ty == rhs_ty 232 && self_ty.is_ref() 233 && self_ty.peel_refs().is_primitive() => 234 { 235 let mut num_refs = 0; 236 let mut tmp_ty = self_ty; 237 while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() { 238 num_refs += 1; 239 tmp_ty = *inner_ty; 240 } 241 let deref = "*".repeat(num_refs); 242 243 if let Ok(call_str) = 244 ccx.tcx.sess.source_map().span_to_snippet(span) 245 { 246 if let Some(eq_idx) = call_str.find("==") { 247 if let Some(rhs_idx) = call_str[(eq_idx + 2)..] 248 .find(|c: char| !c.is_whitespace()) 249 { 250 let rhs_pos = span.lo() 251 + BytePos::from_usize(eq_idx + 2 + rhs_idx); 252 let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos); 253 sugg = Some(errors::ConsiderDereferencing { 254 deref, 255 span: span.shrink_to_lo(), 256 rhs_span, 257 }); 258 } 259 } 260 } 261 } 262 _ => {} 263 } 264 } 265 tcx.sess.create_err(errors::NonConstOperator { 266 span, 267 kind: ccx.const_kind(), 268 sugg, 269 }) 270 }; 271 272 diag_trait(&mut err, self_ty, trait_id); 273 err 274 } 275 CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => { 276 // Check first whether the source is accessible (issue #87060) 277 let target = if tcx.sess.source_map().is_span_accessible(deref_target) { 278 Some(deref_target) 279 } else { 280 None 281 }; 282 283 let mut err = tcx.sess.create_err(errors::NonConstDerefCoercion { 284 span, 285 ty: self_ty, 286 kind: ccx.const_kind(), 287 target_ty: deref_target_ty, 288 deref_target: target, 289 }); 290 291 diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span))); 292 err 293 } 294 _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => ccx 295 .tcx 296 .sess 297 .create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }), 298 _ => ccx.tcx.sess.create_err(errors::NonConstFnCall { 299 span, 300 def_path_str: ccx.tcx.def_path_str_with_substs(callee, substs), 301 kind: ccx.const_kind(), 302 }), 303 }; 304 305 err.note(format!( 306 "calls in {}s are limited to constant functions, \ 307 tuple structs and tuple variants", 308 ccx.const_kind(), 309 )); 310 311 if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() { 312 err.help(format!( 313 "add `#![feature({})]` to the crate attributes to enable", 314 feature, 315 )); 316 } 317 318 if let ConstContext::Static(_) = ccx.const_kind() { 319 err.note("consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` crate: https://crates.io/crates/once_cell"); 320 } 321 322 err 323 } 324 } 325 326 /// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function. 327 /// 328 /// Contains the name of the feature that would allow the use of this function. 329 #[derive(Debug)] 330 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>); 331 332 impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>333 fn build_error( 334 &self, 335 ccx: &ConstCx<'_, 'tcx>, 336 span: Span, 337 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 338 let FnCallUnstable(def_id, feature) = *self; 339 340 let mut err = ccx 341 .tcx 342 .sess 343 .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) }); 344 345 if ccx.is_const_stable_const_fn() { 346 err.help("const-stable functions can only call other const-stable functions"); 347 } else if ccx.tcx.sess.is_nightly_build() { 348 if let Some(feature) = feature { 349 err.help(format!( 350 "add `#![feature({})]` to the crate attributes to enable", 351 feature 352 )); 353 } 354 } 355 356 err 357 } 358 } 359 360 #[derive(Debug)] 361 pub struct Generator(pub hir::GeneratorKind); 362 impl<'tcx> NonConstOp<'tcx> for Generator { status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status363 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { 364 if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { 365 Status::Unstable(sym::const_async_blocks) 366 } else { 367 Status::Forbidden 368 } 369 } 370 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>371 fn build_error( 372 &self, 373 ccx: &ConstCx<'_, 'tcx>, 374 span: Span, 375 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 376 let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind()); 377 if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 { 378 ccx.tcx.sess.create_feature_err( 379 errors::UnallowedOpInConstContext { span, msg }, 380 sym::const_async_blocks, 381 ) 382 } else { 383 ccx.tcx.sess.create_err(errors::UnallowedOpInConstContext { span, msg }) 384 } 385 } 386 } 387 388 #[derive(Debug)] 389 pub struct HeapAllocation; 390 impl<'tcx> NonConstOp<'tcx> for HeapAllocation { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>391 fn build_error( 392 &self, 393 ccx: &ConstCx<'_, 'tcx>, 394 span: Span, 395 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 396 ccx.tcx.sess.create_err(errors::UnallowedHeapAllocations { 397 span, 398 kind: ccx.const_kind(), 399 teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()), 400 }) 401 } 402 } 403 404 #[derive(Debug)] 405 pub struct InlineAsm; 406 impl<'tcx> NonConstOp<'tcx> for InlineAsm { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>407 fn build_error( 408 &self, 409 ccx: &ConstCx<'_, 'tcx>, 410 span: Span, 411 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 412 ccx.tcx.sess.create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() }) 413 } 414 } 415 416 #[derive(Debug)] 417 pub struct LiveDrop<'tcx> { 418 pub dropped_at: Option<Span>, 419 pub dropped_ty: Ty<'tcx>, 420 } 421 impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>422 fn build_error( 423 &self, 424 ccx: &ConstCx<'_, 'tcx>, 425 span: Span, 426 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 427 ccx.tcx.sess.create_err(errors::LiveDrop { 428 span, 429 dropped_ty: self.dropped_ty, 430 kind: ccx.const_kind(), 431 dropped_at: self.dropped_at, 432 }) 433 } 434 } 435 436 #[derive(Debug)] 437 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to 438 /// the final value of the constant. 439 pub struct TransientCellBorrow; 440 impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status441 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { 442 Status::Unstable(sym::const_refs_to_cell) 443 } importance(&self) -> DiagnosticImportance444 fn importance(&self) -> DiagnosticImportance { 445 // The cases that cannot possibly work will already emit a `CellBorrow`, so we should 446 // not additionally emit a feature gate error if activating the feature gate won't work. 447 DiagnosticImportance::Secondary 448 } build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>449 fn build_error( 450 &self, 451 ccx: &ConstCx<'_, 'tcx>, 452 span: Span, 453 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 454 ccx.tcx 455 .sess 456 .create_feature_err(errors::InteriorMutabilityBorrow { span }, sym::const_refs_to_cell) 457 } 458 } 459 460 #[derive(Debug)] 461 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to 462 /// the final value of the constant, and thus we cannot allow this (for now). We may allow 463 /// it in the future for static items. 464 pub struct CellBorrow; 465 impl<'tcx> NonConstOp<'tcx> for CellBorrow { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>466 fn build_error( 467 &self, 468 ccx: &ConstCx<'_, 'tcx>, 469 span: Span, 470 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 471 // FIXME: Maybe a more elegant solution to this if else case 472 if let hir::ConstContext::Static(_) = ccx.const_kind() { 473 ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer { 474 span, 475 opt_help: Some(()), 476 kind: ccx.const_kind(), 477 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), 478 }) 479 } else { 480 ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer { 481 span, 482 opt_help: None, 483 kind: ccx.const_kind(), 484 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()), 485 }) 486 } 487 } 488 } 489 490 #[derive(Debug)] 491 /// This op is for `&mut` borrows in the trailing expression of a constant 492 /// which uses the "enclosing scopes rule" to leak its locals into anonymous 493 /// static or const items. 494 pub struct MutBorrow(pub hir::BorrowKind); 495 496 impl<'tcx> NonConstOp<'tcx> for MutBorrow { status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status497 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { 498 Status::Forbidden 499 } 500 importance(&self) -> DiagnosticImportance501 fn importance(&self) -> DiagnosticImportance { 502 // If there were primary errors (like non-const function calls), do not emit further 503 // errors about mutable references. 504 DiagnosticImportance::Secondary 505 } 506 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>507 fn build_error( 508 &self, 509 ccx: &ConstCx<'_, 'tcx>, 510 span: Span, 511 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 512 match self.0 { 513 hir::BorrowKind::Raw => ccx.tcx.sess.create_err(errors::UnallowedMutableRefsRaw { 514 span, 515 kind: ccx.const_kind(), 516 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), 517 }), 518 hir::BorrowKind::Ref => ccx.tcx.sess.create_err(errors::UnallowedMutableRefs { 519 span, 520 kind: ccx.const_kind(), 521 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()), 522 }), 523 } 524 } 525 } 526 527 #[derive(Debug)] 528 pub struct TransientMutBorrow(pub hir::BorrowKind); 529 530 impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow { status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status531 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { 532 Status::Unstable(sym::const_mut_refs) 533 } 534 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>535 fn build_error( 536 &self, 537 ccx: &ConstCx<'_, 'tcx>, 538 span: Span, 539 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 540 let kind = ccx.const_kind(); 541 match self.0 { 542 hir::BorrowKind::Raw => ccx.tcx.sess.create_feature_err( 543 errors::TransientMutBorrowErrRaw { span, kind }, 544 sym::const_mut_refs, 545 ), 546 hir::BorrowKind::Ref => ccx.tcx.sess.create_feature_err( 547 errors::TransientMutBorrowErr { span, kind }, 548 sym::const_mut_refs, 549 ), 550 } 551 } 552 } 553 554 #[derive(Debug)] 555 pub struct MutDeref; 556 impl<'tcx> NonConstOp<'tcx> for MutDeref { status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status557 fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { 558 Status::Unstable(sym::const_mut_refs) 559 } 560 importance(&self) -> DiagnosticImportance561 fn importance(&self) -> DiagnosticImportance { 562 // Usually a side-effect of a `TransientMutBorrow` somewhere. 563 DiagnosticImportance::Secondary 564 } 565 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>566 fn build_error( 567 &self, 568 ccx: &ConstCx<'_, 'tcx>, 569 span: Span, 570 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 571 ccx.tcx.sess.create_feature_err( 572 errors::MutDerefErr { span, kind: ccx.const_kind() }, 573 sym::const_mut_refs, 574 ) 575 } 576 } 577 578 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`. 579 #[derive(Debug)] 580 pub struct PanicNonStr; 581 impl<'tcx> NonConstOp<'tcx> for PanicNonStr { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>582 fn build_error( 583 &self, 584 ccx: &ConstCx<'_, 'tcx>, 585 span: Span, 586 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 587 ccx.tcx.sess.create_err(errors::PanicNonStrErr { span }) 588 } 589 } 590 591 /// Comparing raw pointers for equality. 592 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on 593 /// allocation base addresses that are not known at compile-time. 594 #[derive(Debug)] 595 pub struct RawPtrComparison; 596 impl<'tcx> NonConstOp<'tcx> for RawPtrComparison { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>597 fn build_error( 598 &self, 599 ccx: &ConstCx<'_, 'tcx>, 600 span: Span, 601 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 602 // FIXME(const_trait_impl): revert to span_bug? 603 ccx.tcx.sess.create_err(errors::RawPtrComparisonErr { span }) 604 } 605 } 606 607 #[derive(Debug)] 608 pub struct RawMutPtrDeref; 609 impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref { status_in_item(&self, _: &ConstCx<'_, '_>) -> Status610 fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { 611 Status::Unstable(sym::const_mut_refs) 612 } 613 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>614 fn build_error( 615 &self, 616 ccx: &ConstCx<'_, 'tcx>, 617 span: Span, 618 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 619 feature_err( 620 &ccx.tcx.sess.parse_sess, 621 sym::const_mut_refs, 622 span, 623 format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),), 624 ) 625 } 626 } 627 628 /// Casting raw pointer or function pointer to an integer. 629 /// Not currently intended to ever be allowed, even behind a feature gate: operation depends on 630 /// allocation base addresses that are not known at compile-time. 631 #[derive(Debug)] 632 pub struct RawPtrToIntCast; 633 impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>634 fn build_error( 635 &self, 636 ccx: &ConstCx<'_, 'tcx>, 637 span: Span, 638 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 639 ccx.tcx.sess.create_err(errors::RawPtrToIntErr { span }) 640 } 641 } 642 643 /// An access to a (non-thread-local) `static`. 644 #[derive(Debug)] 645 pub struct StaticAccess; 646 impl<'tcx> NonConstOp<'tcx> for StaticAccess { status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status647 fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { 648 if let hir::ConstContext::Static(_) = ccx.const_kind() { 649 Status::Allowed 650 } else { 651 Status::Forbidden 652 } 653 } 654 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>655 fn build_error( 656 &self, 657 ccx: &ConstCx<'_, 'tcx>, 658 span: Span, 659 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 660 ccx.tcx.sess.create_err(errors::StaticAccessErr { 661 span, 662 kind: ccx.const_kind(), 663 teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()), 664 }) 665 } 666 } 667 668 /// An access to a thread-local `static`. 669 #[derive(Debug)] 670 pub struct ThreadLocalAccess; 671 impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess { build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>672 fn build_error( 673 &self, 674 ccx: &ConstCx<'_, 'tcx>, 675 span: Span, 676 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 677 ccx.tcx.sess.create_err(errors::NonConstOpErr { span }) 678 } 679 } 680 681 /// Types that cannot appear in the signature or locals of a `const fn`. 682 pub mod ty { 683 use super::*; 684 685 #[derive(Debug)] 686 pub struct MutRef(pub mir::LocalKind); 687 impl<'tcx> NonConstOp<'tcx> for MutRef { status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status688 fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { 689 Status::Unstable(sym::const_mut_refs) 690 } 691 importance(&self) -> DiagnosticImportance692 fn importance(&self) -> DiagnosticImportance { 693 match self.0 { 694 mir::LocalKind::Temp => DiagnosticImportance::Secondary, 695 mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { 696 DiagnosticImportance::Primary 697 } 698 } 699 } 700 build_error( &self, ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>701 fn build_error( 702 &self, 703 ccx: &ConstCx<'_, 'tcx>, 704 span: Span, 705 ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { 706 feature_err( 707 &ccx.tcx.sess.parse_sess, 708 sym::const_mut_refs, 709 span, 710 format!("mutable references are not allowed in {}s", ccx.const_kind()), 711 ) 712 } 713 } 714 } 715