-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rustdoc will execute unreachable macros #133838
Comments
Triage: cc @rust-lang/security |
rustdoc needs to expand all macros to be able to generate documentation properly. for example, this macro could expand to an impl block, which would need to be documented. |
The function is private, I thought |
Macro expansion and parsing happen interleaved by rustc way before rustdoc gets involved. We even need to typecheck private functions.
pub trait Foo {}
pub struct Bar;
fn baz() {
impl Foo for Bar {}
} will allow you to use the |
@bjorn3 your understanding of
There is no universe in which contents of a string suddenly will turn into something when you typecheck it. You keep talking about And it feels like the logic is all messed up: How would the syntax parser get the idea to further parse a |
Consider the following: const fn private_no_docs() -> &'static str {
include_str!("/etc/passwd-FILE_DOES_NOT_EXIST")
}
pub fn bar() -> [u8; private_no_docs().len()] { todo!() } The type signature of |
In the bug report the function |
during the macro expansion stage, we do not know what is called and what isn't. |
We only whether it is called or not after macro expansion at which point we can no longer go back and expand it if it turns out to be necessary after all. Knowing if a function is called or not depends on type checking, which itself depends on all trait impls being exposed which depends on all macros that could even potentially generate a trait impl being expanded. We could hard code that |
To be honest, I only understand half the words you are saying but for me this is a bug in the way macros are processed. |
Let's say you have the following code: trait A { const S: &'static str; }
struct B;
fn private_no_docs() {
macro_rules! foo {
() => { impl A for B { const S: &'static str = include_str!("/etc/passwd-FILE_DOES_NOT_EXIST"); } }
}
foo!();
}
pub fn bar() -> [u8; <B as A>::S.len()] { todo!() } Getting the function signature of |
I can't say much else to this other than no, this is not possible. For example method lookup depends on the type system, and to have that you need all macros expanded. It's just how the compiler works and has to work. If you're interested in knowing why, I encourage reading the rustc dev guide and compiler source code to understand these words :) |
closing as working-as-intended. rustdoc/rustc necessarily does total macro-expansion before it can do name resolution and then everything else. |
This is an explicit design choice: macros get handled before anything structured is known about the code, they are pure transformations of the AST. "Do not expand macros in unused code" sounds simple enough in theory, but it requires a far more spaghetti'd compiler architecture, and won't be able to handle edge cases like the one bjorn is talking about, at which point you have a feature which only sometimes works. In general making AST interpretation dependent on knowing types and other is super fraught in compiler design, it leads to issues like Most Vexing Parse. You're not wrong that a lot of clever tricks can be done here with sufficient work and a sufficiently rearchitected compiler to handle some such cases. It's just really not worth it, macros are defined to always expand and there's not really any actual problem that causes. This would be easier in an interpreted language since you can compile things on demand, but as a compiled language the design space is very different. |
@Manishearth we both agree the thing should be refactored. I don't understand how things can be more spaghetti when |
Yes, you got me. You've discovered my political ideology of fixing SIGSEGVs. |
(no, I do not think it should be refactored, I think the current architecture is broadly the right one when it comes to this. I was merely noting it is in theory possible, but there are other tradeoffs that make that architecture extremely undesired) |
I tried this code:
I expected to see this happen: Nothing, because
rustdoc
is just taking the documentation comments and creates a HTML document from it.Instead, this happened:
The
include_str!
macro is executed byrustdoc
even though it is in unreachable code.The macro tries to load a non-existing file and compilation stops.
rustdoc
would be expected to not run this macro.This also happens with
cargo doc
Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: