rust-lang/rust · error · syn::Error
Expected a string literal
Error message
Expected a string literal
What it means
Thrown by doc_comment_from_desc (query.rs:309-317) when auto-generating a doc comment for a query that was declared without an explicit doc comment. The function takes the desc block's expression list and requires its first expression to be a string literal (Lit::Str); the match arm at query.rs:312-316 returns Err for anything else. This path is only reached when no /// doc comment is present (query.rs:109-111), because the desc string is used as a fallback description.
Source
Thrown at compiler/rustc_macros/src/query.rs:316
eval_always: #eval_always,
feedable: #feedable,
handle_cycle_error: #handle_cycle_error,
no_force: #no_force,
no_hash: #no_hash,
returns_error_guaranteed: #returns_error_guaranteed,
separate_provide_extern: #separate_provide_extern,
// tidy-alphabetical-end
}
}
fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attribute> {
use ::syn::*;
let mut iter = list.iter();
let format_str: String = match iter.next() {
Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
}
_ => return Err(Error::new(list.span(), "Expected a string literal")),
};
let mut fmt_fragments = format_str.split("{}");
let mut doc_string = fmt_fragments.next().unwrap().to_string();
iter.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
|(tts, next_fmt_fragment)| {
use ::core::fmt::Write;
write!(
&mut doc_string,
" `{}` {}",
tts.to_string().replace(" . ", "."),
next_fmt_fragment,
)
.unwrap();
},
);
let doc_string = format!("[query description - consider adding a doc-comment!] {doc_string}");
Ok(parse_quote! { #[doc = #doc_string] })
}View on GitHub (pinned to 22057b88b0)
Solutions
- Add an explicit /// doc comment above the query, which bypasses the auto-generation path entirely (query.rs:109).
- Otherwise ensure the first expression inside the desc { } block is a string literal, e.g. `desc { "computing {}", tcx.item_path(key) }`.
- Keep format placeholders as `{}` (the code rewrites `` `{}` `` back to `{}` at query.rs:314, so either form works, but it must be a literal).
Example fix
// before
query type_of(key: DefId) -> Ty<'tcx> {
desc { tcx.def_path_str(key), "type of {}" }
}
// after
query type_of(key: DefId) -> Ty<'tcx> {
desc { "type of {}", tcx.def_path_str(key) }
} Defensive patterns
Strategy: type-guard
Validate before calling
// The macro only accepts a *literal* string token; never a const, ident, or expr.
// Good: #[query(name = "dep_graph")]
// Bad: const N = "dep_graph"; #[query(name = N)]
fn assert_literal(s: &'static str) -> &'static str { s } Type guard
// Narrow to a compile-time &str literal so non-literal expressions fail to compile
fn require_str_literal<S: AsRef<str>>(s: S) -> &str { s.as_ref() } Prevention
- Always quote the argument passed to the query macro
- Never pass a const/ident/expression where a string literal is expected
- When copying a query declaration, re-type the string rather than aliasing it
When it happens
Trigger: Declaring a query without a /// doc comment and giving a desc block whose first expression is not a string literal, e.g. `query foo(k: K) -> V { desc { tcx.foo(k), "x" } }` (variable before the format string) or `desc { 42 }`. The first element must be a string literal like `"{}"`.
Common situations: Adding a new query to rustc and forgetting the doc comment while also writing the desc block in an unusual order; using a non-literal format string (e.g. a const or macro result) as the first desc argument. End users never see this; it is a rustc-internal compile error.
Related errors
- duplicate modifier
- unknown query modifier
- attributes not supported on queries
- attributes must be outer attributes (`///`), not inner attri
- {:?} shouldn't exist here
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/3b30689c8d342b2a.json.
Report an issue: GitHub.