rust-lang / rust-lang/rust

Inner attributes react strangely with `include!()`

Open
#117,464 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-diagnostics A-macros C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

I tried this code:

        let mut bindings_file = dest_dir.clone();
        bindings_file.push(&format!("pg{}.rs", major_version));
        write_rs_file(
            rewritten_items.clone(),
            &bindings_file,
            quote! {
                #![allow(clippy::all)]
                //! All robots and linters must shut the *.h up
                //! to all machines:
                //! - you do not speak unless spoken to!
                //! - and I will NEVER speak to you!
                //! I am a divine being!
                //! you are an object!
                //! you have no right to speak my holy tongue!
                use crate as pg_sys;
                use crate::{Datum, Oid, PgNode};
            },
        )
        .wrap_err_with(|| {
            format!(
                "Unable to write bindings file for pg{} to `{}`",
                major_version,
                bindings_file.display()
            )
        })?;

As you might guess, some code is generated through bindgen on-the-spot and then included into another source file via a mechanism like:

#[cfg(all(feature = "pg13", not(docsrs)))]
pub(crate) mod pg13 {
    include!(concat!(env!("OUT_DIR"), "/pg13.rs"));
}

I expected to see this happen: Not only would my generated code be accepted by Rust, but it would silence all clippy warnings in that file, because it's literally the first item in that file, and when included, it should be the first item in that module. Thus, it seems like it should be a valid source annotation. After all, this code works:

mod something {
    #![allow(unused)]
    
    fn bad_func() {
        let mut buf = [230, 156, 0]; // should be 157
        println!("朝, {:?}", std::str::from_utf8(&buf));
    }
}

Instead, this happened:

Big "inner attribute not allowed" failure
$ cargo check
    Checking pgrx-pg-sys v0.11.0 (/home/jubilee/tcdi/pgrx/pgrx-pg-sys)
error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:1:1
  |
1 | #![allow(clippy::all)]
  | ^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
1 - #![allow(clippy::all)]
1 + #[allow(clippy::all)]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:2:1
  |
2 | #![doc = r" All robots and linters must shut the *.h up"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
2 - #![doc = r" All robots and linters must shut the *.h up"]
2 + #[doc = r" All robots and linters must shut the *.h up"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:3:1
  |
3 | #![doc = r" to all machines:"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
3 - #![doc = r" to all machines:"]
3 + #[doc = r" to all machines:"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:4:1
  |
4 | #![doc = r" - you do not speak unless spoken to!"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
4 - #![doc = r" - you do not speak unless spoken to!"]
4 + #[doc = r" - you do not speak unless spoken to!"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:5:1
  |
5 | #![doc = r" - and I will NEVER speak to you!"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
5 - #![doc = r" - and I will NEVER speak to you!"]
5 + #[doc = r" - and I will NEVER speak to you!"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:6:1
  |
6 | #![doc = r" I am a divine being!"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
6 - #![doc = r" I am a divine being!"]
6 + #[doc = r" I am a divine being!"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:7:1
  |
7 | #![doc = r" you are an object!"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 | #![doc = r" you have no right to speak my holy tongue!"]
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
7 - #![doc = r" you are an object!"]
7 + #[doc = r" you are an object!"]
  |

error: an inner attribute is not permitted in this context
 --> /home/jubilee/tcdi/pgrx/target/debug/build/pgrx-pg-sys-3e502dbdad64018b/out/pg13.rs:8:1
  |
8 | #![doc = r" you have no right to speak my holy tongue!"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9 | use crate as pg_sys;
  | -------------------- the inner attribute doesn't annotate this `use` import
  |
  = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
help: to annotate the `use` import, change the attribute from inner to outer style
  |
8 - #![doc = r" you have no right to speak my holy tongue!"]
8 + #[doc = r" you have no right to speak my holy tongue!"]
  |

error: could not compile `pgrx-pg-sys` (lib) due to 8 previous errors

For now I added the annotation inside the module, but this seems confusing. What's especially confusing is it trying to warn me about using an "inner attribute" on a use, when I was trying to avoid it thinking that, but alas it seems there's no real surefire way to make that happen, having fiddled with it for a while trying to make that work.

If there is no bug in what rustc accepts, here, there sure is a diagnostic error.

Meta

rustc --version --verbose:

rustc 1.75.0-nightly (31bc7e2c4 2023-10-30)
binary: rustc
commit-hash: 31bc7e2c47e82798a392c770611975a6883132c8
commit-date: 2023-10-30
host: x86_64-unknown-linux-gnu
release: 1.75.0-nightly
LLVM version: 17.0.3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reducing the included-module example around include!() and run cargo check with the reported inner attributes. Trace how rustc parses inner attributes in included source, then determine whether the behavior or diagnostic is incorrect; done means a confirmed resolution with coverage for the reproducer.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.