{"id":"2407d625703075e1","repo":"rust-lang/rust","slug":"argument-to-panic-in-a-const-context-must-hav","errorCode":null,"errorMessage":"argument to `panic!()` in a const context must have type `&str`","messagePattern":"argument to `panic!\\(\\)` in a const context must have type `&str`","errorType":"validation","errorClass":"PanicNonStrErr","httpStatus":null,"severity":"error","filePath":"compiler/rustc_const_eval/src/diagnostics.rs","lineNumber":135,"sourceCode":"#[note(\"at compile-time, pointers do not have an integer value\")]\n#[note(\n    \"avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior\"\n)]\npub(crate) struct RawPtrToIntErr {\n    #[primary_span]\n    pub span: Span,\n}\n\n#[derive(Diagnostic)]\n#[diag(\"pointers cannot be reliably compared during const eval\")]\n#[note(\"see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information\")]\npub(crate) struct RawPtrComparisonErr {\n    #[primary_span]\n    pub span: Span,\n}\n\n#[derive(Diagnostic)]\n#[diag(\"argument to `panic!()` in a const context must have type `&str`\")]\npub(crate) struct PanicNonStrErr {\n    #[primary_span]\n    pub span: Span,\n}\n\n#[derive(Diagnostic)]\n#[diag(r#\"function pointer calls are not allowed in {$kind}s\"#)]\npub(crate) struct UnallowedFnPointerCall {\n    #[primary_span]\n    pub span: Span,\n    pub kind: ConstContext,\n}\n\n#[derive(Diagnostic)]\n#[diag(\"`{$def_path}` is not yet stable as a const fn\")]\npub(crate) struct UnstableConstFn {\n    #[primary_span]\n    pub span: Span,","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_const_eval/src/diagnostics.rs#L117-L153","documentation":"Reported by the const-eval checker via the PanicNonStr op whenever the interpreter encounters a call to the panic lang item inside a const/static/const-fn context and the first argument is not a &str. In const eval only the trivial panic!(\"literal\") / panic!(str_expr) form is allowed; formatted panics and panics with non-string payloads are rejected because the const-eval panic machinery cannot format or carry arbitrary payloads at compile time.","triggerScenarios":"rustc_const_eval::check_consts evaluates a const item (const, static, const fn body, array length, inline const block) and hits R::PanicNonStr, i.e. a panic!() call whose first argument's type is not &str. Examples: panic!(0u32), panic!(\"{}\", x), panic!(some_int), panic!(format!(...)), or a macro expanding to such a panic.","commonSituations":"Refactoring a runtime panic to compile-time; using assert! in a const context where the message formats a value; stabilizing code from runtime into const fn; depending on a macro that emits panic! with a non-string first arg.","solutions":["Replace the panic with a &str literal or a const &str expression","For formatted messages, pre-format at runtime instead of const, or use a static string with no interpolation","Replace panic! with const-friendly const_panic crate patterns if the use case really needs it","If the panic comes from a macro, expand it and pass a plain &str"],"exampleFix":"// before\nconst N: u32 = if FLAG { 1 } else { panic!(\"bad: {}\", 0) };\n// after\nconst N: u32 = if FLAG { 1 } else { panic!(\"FLAG must be set\") };","handlingStrategy":"type-guard","validationCode":"// const-eval requires panic!() message to be &str. Pre-check panic! argument\n// types with a build-script / clippy-style pass, or statically in your source:\n//\n// In const fn, only use string literals:\n//   const fn f(x: i32) -> i32 {\n//       if x < 0 { panic!(\"negative\"); }   // OK: &str literal\n//   }\n//\n// Forbidden in const context:\n//   panic!(format!(\"neg: {}\", x));   // String, not &str\n//   panic!(\"{}\", x);                // formatting args not allowed\n","typeGuard":"// AST-level guard for macros generating const fn bodies: reject non-&str panic payloads.\n// In procedural-macro land:\nenum PanicPayload {\n    StrLit(String),     // accepted in const context\n    FormatArgs,         // rejected in const context\n    Expr,               // rejected in const context\n}\n\nfn classify_panic_payload(mac: &syn::Macro) -> PanicPayload {\n    if mac.tokens.is_empty() {\n        return PanicPayload::StrLit(String::new());\n    }\n    // single string literal token -> &str\n    let mut tts = mac.tokens.clone().into_iter();\n    if let Some(tt::TokenTree::Literal(lit)) = tts.next() {\n        let s = lit.to_string();\n        if s.starts_with('\"') && s.ends_with('\"') && tts.next().is_none() {\n            return PanicPayload::StrLit(s);\n        }\n    }\n    if mac.path.is_ident(\"format\") || mac.path.is_ident(\"format_args\") {\n        return PanicPayload::FormatArgs;\n    }\n    PanicPayload::Expr\n}\n\nfn is_const_safe_panic(mac: &syn::Macro) -> bool {\n    matches!(classify_panic_payload(mac), PanicPayload::StrLit(_))\n}","tryCatchPattern":"// This is a compile-time type error; there is no runtime catch. Use a build.rs\n// or a lint pass that fails fast:\nfn reject_non_str_const_panic(crate_src: &str) -> Result<(), String> {\n    let file = syn::parse_file(crate_src).map_err(|e| e.to_string())?;\n    for item in &file.items {\n        if let syn::Item::Fn(f) = item {\n            let is_const = f.sig.constness.is_some();\n            for stmt in &f.block.stmts {\n                // walk and find panic!() macro invocations; left as exercise for the\n                // real linter; on match: if !is_const_safe_panic(&mac) && is_const { return Err(...) }\n                let _ = (stmt, is_const);\n            }\n        }\n    }\n    Ok(())\n}","preventionTips":["In const fn, always pass a plain string literal to panic!(): panic!(\"msg\").","Avoid format!(), format_args!(), and interpolated values inside const fn panic! — they are not const-evaluable as &str today.","If you need dynamic context in a const panic, encode it as a fixed set of allowed literals and select with a const if/match.","Add a clippy::deny or a custom lint on the macro so the failure surfaces in CI before it reaches rustc_const_eval.","Document every const fn with the constraint that panic payloads must be &str."],"tags":["const-eval","panic","compiler-error","diagnostic"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}