Skip to content

Adding an attribute to a macro_exported macro and reexporting it incorrectly triggers the macro_expanded_macro_exports_accessed_by_absolute_paths error #98291

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

Open
jakobrs opened this issue Jun 20, 2022 · 8 comments
Assignees
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-resolve Area: Name/path resolution done by `rustc_resolve` specifically C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@jakobrs
Copy link

jakobrs commented Jun 20, 2022

I tried this code:

#[rustfmt::skip]    // <- The code compiles if this attribute is removed
#[macro_export]
macro_rules! _a {
    () => {
        "Hello world"
    };
}

pub use _a as a;

fn main() {
    println!(a!());
}

(https://gist.github.com/jakobrs/8bcaf3448431126005e16ac678f769c5)

I expected to see this happen: The code should compile successfully.

Instead, this happened: The macro_expanded_macro_exports_accessed_by_absolute_paths error is triggered.

Full error message
error: cannot determine resolution for the macro `a`
  --> ./b.rs:12:14
   |
12 |     println!(a!());
   |              ^
   |
   = note: import resolution is stuck, try simplifying macro imports

error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
 --> ./b.rs:9:9
  |
9 | pub use _a as a;
  |         ^^^^^^^
  |
  = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
 --> ./b.rs:3:1
  |
3 | / macro_rules! _a {
4 | |     () => {
5 | |         "Hello world"
6 | |     };
7 | | }
  | |_^

error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
  --> ./b.rs:12:14
   |
12 |     println!(a!());
   |              ^
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
  --> ./b.rs:3:1
   |
3  | / macro_rules! _a {
4  | |     () => {
5  | |         "Hello world"
6  | |     };
7  | | }
   | |_^

error: aborting due to 3 previous errors

Meta

This happens with Rust 1.60, 1.61 and nightly (bb8c2f4 2022-06-19)
rustc --version --verbose:

# Nightly

rustc 1.63.0-nightly (bb8c2f411 2022-06-19)
binary: rustc
commit-hash: bb8c2f41174caceec00c28bc6c5c20ae9f9a175c
commit-date: 2022-06-19
host: x86_64-unknown-linux-gnu
release: 1.63.0-nightly
LLVM version: 14.0.5

# Stable

rustc 1.61.0 (fe5b13d68 2022-05-18)
binary: rustc
commit-hash: fe5b13d681f25ee6474be29d748c65adcd91f69e
commit-date: 2022-05-18
host: x86_64-unknown-linux-gnu
release: 1.61.0
LLVM version: 14.0.0
@jakobrs jakobrs added the C-bug Category: This is a bug. label Jun 20, 2022
jakobrs added a commit to THE-NIO/cf_utils that referenced this issue Jun 20, 2022
@fmease fmease added A-resolve Area: Name/path resolution done by `rustc_resolve` specifically A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) labels Jan 26, 2024
@fmease
Copy link
Member

fmease commented Jan 26, 2024

Triage: No longer triggers macro_expanded_macro_exports_accessed_by_absolute_paths.
Current output:

error: cannot determine resolution for the macro `a`
  --> src/main.rs:12:14
   |
12 |     println!(a!());
   |              ^
   |
   = note: import resolution is stuck, try simplifying macro imports

@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-attributes Area: Attributes (`#[…]`, `#![…]`) labels Feb 17, 2024
@fmease
Copy link
Member

fmease commented Feb 17, 2024

Related reproducer from #121219 (different error):

#[macro_export]
#[rustfmt::skip]
macro_rules! test_macro {
    (()) => { Some(()) };
    (non) => { None };
}

fn main() {
    let t = crate::test_macro!(());
    println!("{:?}", t);
}
error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
 --> src/main.rs:9:13
  |
9 |     let t = crate::test_macro!(());
  |             ^^^^^^^^^^^^^^^^^
  |
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
 --> src/main.rs:3:1
  |
3 | / macro_rules! test_macro {
4 | |     (()) => { Some(()) };
5 | |     (non) => { None };
6 | | }
  | |_^
  = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default

@fmease
Copy link
Member

fmease commented Feb 17, 2024

@bvanjoi, perhaps you're interested in looking into the root cause for this. Pinging you since I know that you love to work on A-resolve issues :)

@bvanjoi
Copy link
Contributor

bvanjoi commented Feb 17, 2024

It's noteworthy that this case had previously induced an ice:

// rustc code.rs --edition=2021

#[rustfmt::skip] 
macro_rules! _a {
    () => {
        "Hello world"
    };
}
use _a as a;
fn main() {
    println!(a!());
}

rustc version:

rustc 1.78.0-nightly (ee9c7c940 2024-02-14)
binary: rustc
commit-hash: ee9c7c940c07d8b67c9a6b2ec930db70dcd23a46
commit-date: 2024-02-14
host: aarch64-apple-darwin
release: 1.78.0-nightly
LLVM version: 18.1.0
Backtrace

thread 'rustc' panicked at compiler/rustc_ast_lowering/src/expr.rs:326:77:
called `Option::unwrap()` on a `None` value
stack backtrace:
   0:        0x103a6438c - std::backtrace::Backtrace::create::h82b61cff75ea3f53
   1:        0x10ce07b08 - std[e09757a2c7ce6988]::panicking::update_hook::<alloc[3a60118b2745d164]::boxed::Box<rustc_driver_impl[dca98f68974adbed]::install_ice_hook::{closure#0}>>::{closure#0}
   2:        0x103a7d134 - std::panicking::rust_panic_with_hook::h5f2e6b6c2894b129
   3:        0x103a7cacc - std::panicking::begin_panic_handler::{{closure}}::hd2a8737cdf27ffdd
   4:        0x103a7a430 - std::sys_common::backtrace::__rust_end_short_backtrace::h750d9d4404a9f361
   5:        0x103a7c870 - _rust_begin_unwind
   6:        0x103ad7c24 - core::panicking::panic_fmt::h0e0e4617759d3b1f
   7:        0x103ad7cac - core::panicking::panic::h32049462625288e3
   8:        0x103ad7bd4 - core::option::unwrap_failed::hf79b7e70b841468a
   9:        0x10c621ff8 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_expr_mut::{closure#0}
  10:        0x10c621974 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_exprs
  11:        0x10c6221dc - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_expr_mut::{closure#0}
  12:        0x10c61f74c - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_stmts
  13:        0x10c61f50c - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_block
  14:        0x10c622708 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_expr_mut::{closure#0}
  15:        0x10c61f74c - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_stmts
  16:        0x10c644918 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_block_expr
  17:        0x10c636438 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_maybe_coroutine_body
  18:        0x10c62e230 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::lower_item_kind
  19:        0x10c648204 - <rustc_ast_lowering[4995b37500c4f80b]::LoweringContext>::with_hir_id_owner::<<rustc_ast_lowering[4995b37500c4f80b]::item::ItemLowerer>::with_lctx<<rustc_ast_lowering[4995b37500c4f80b]::item::ItemLowerer>::lower_item::{closure#0}>::{closure#0}>
  20:        0x10c692b78 - <rustc_ast_lowering[4995b37500c4f80b]::item::ItemLowerer>::lower_node
  21:        0x10c63df44 - rustc_ast_lowering[4995b37500c4f80b]::lower_to_hir
  22:        0x10e01c53c - rustc_query_impl[3b9de3a70d57ed7]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[3b9de3a70d57ed7]::query_impl::hir_crate::dynamic_query::{closure#2}::{closure#0}, rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 8usize]>>
  23:        0x10e0906b0 - <rustc_query_impl[3b9de3a70d57ed7]::query_impl::hir_crate::dynamic_query::{closure#2} as core[8f94067186277a42]::ops::function::FnOnce<(rustc_middle[6b51fbc1467208f7]::ty::context::TyCtxt, ())>>::call_once
  24:        0x10df4fc74 - rustc_query_system[8710640997ca4c58]::query::plumbing::try_execute_query::<rustc_query_impl[3b9de3a70d57ed7]::DynamicConfig<rustc_query_system[8710640997ca4c58]::query::caches::SingleCache<rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 8usize]>>, false, false, false>, rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt, true>
  25:        0x10df29a84 - rustc_query_system[8710640997ca4c58]::query::plumbing::force_query::<rustc_query_impl[3b9de3a70d57ed7]::DynamicConfig<rustc_query_system[8710640997ca4c58]::query::caches::SingleCache<rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 8usize]>>, false, false, false>, rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt>
  26:        0x10dffeb4c - <rustc_query_impl[3b9de3a70d57ed7]::plumbing::query_callback<rustc_query_impl[3b9de3a70d57ed7]::query_impl::hir_crate::QueryType>::{closure#0} as core[8f94067186277a42]::ops::function::FnOnce<(rustc_middle[6b51fbc1467208f7]::ty::context::TyCtxt, rustc_query_system[8710640997ca4c58]::dep_graph::dep_node::DepNode)>>::call_once
  27:        0x10e0f0f38 - <rustc_query_system[8710640997ca4c58]::dep_graph::graph::DepGraphData<rustc_middle[6b51fbc1467208f7]::dep_graph::DepsType>>::try_mark_previous_green::<rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt>
  28:        0x10e0f0f80 - <rustc_query_system[8710640997ca4c58]::dep_graph::graph::DepGraphData<rustc_middle[6b51fbc1467208f7]::dep_graph::DepsType>>::try_mark_previous_green::<rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt>
  29:        0x10e0f0d00 - <rustc_query_system[8710640997ca4c58]::dep_graph::graph::DepGraphData<rustc_middle[6b51fbc1467208f7]::dep_graph::DepsType>>::try_mark_green::<rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt>
  30:        0x10df2be70 - rustc_query_system[8710640997ca4c58]::query::plumbing::ensure_must_run::<rustc_query_impl[3b9de3a70d57ed7]::DynamicConfig<rustc_query_system[8710640997ca4c58]::query::caches::SingleCache<rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 12usize]>>, false, false, false>, rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt>
  31:        0x10e0b15ec - rustc_query_impl[3b9de3a70d57ed7]::query_impl::entry_fn::get_query_incr::__rust_end_short_backtrace
  32:        0x10d56a250 - <rustc_session[34d2f7c8b2ca9bde]::session::Session>::time::<(), rustc_interface[1589e896c9a48ab2]::passes::analysis::{closure#0}::{closure#1}::{closure#0}::{closure#6}::{closure#0}>
  33:        0x10d540870 - std[e09757a2c7ce6988]::panicking::try::<(), core[8f94067186277a42]::panic::unwind_safe::AssertUnwindSafe<rustc_interface[1589e896c9a48ab2]::passes::analysis::{closure#0}::{closure#0}::{closure#0}>>
  34:        0x10d501a4c - <rustc_data_structures[5a29570388e79f5e]::sync::parallel::ParallelGuard>::run::<(), rustc_interface[1589e896c9a48ab2]::passes::analysis::{closure#0}::{closure#0}::{closure#0}>
  35:        0x10d56a9dc - <rustc_session[34d2f7c8b2ca9bde]::session::Session>::time::<(), rustc_interface[1589e896c9a48ab2]::passes::analysis::{closure#0}>
  36:        0x10d4eb618 - rustc_interface[1589e896c9a48ab2]::passes::analysis
  37:        0x10e01c250 - rustc_query_impl[3b9de3a70d57ed7]::plumbing::__rust_begin_short_backtrace::<rustc_query_impl[3b9de3a70d57ed7]::query_impl::analysis::dynamic_query::{closure#2}::{closure#0}, rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 1usize]>>
  38:        0x10e1af0b4 - <rustc_query_impl[3b9de3a70d57ed7]::query_impl::analysis::dynamic_query::{closure#2} as core[8f94067186277a42]::ops::function::FnOnce<(rustc_middle[6b51fbc1467208f7]::ty::context::TyCtxt, ())>>::call_once
  39:        0x10df4c7a8 - rustc_query_system[8710640997ca4c58]::query::plumbing::try_execute_query::<rustc_query_impl[3b9de3a70d57ed7]::DynamicConfig<rustc_query_system[8710640997ca4c58]::query::caches::SingleCache<rustc_middle[6b51fbc1467208f7]::query::erase::Erased<[u8; 1usize]>>, false, false, false>, rustc_query_impl[3b9de3a70d57ed7]::plumbing::QueryCtxt, true>
  40:        0x10e0ae930 - rustc_query_impl[3b9de3a70d57ed7]::query_impl::analysis::get_query_incr::__rust_end_short_backtrace
  41:        0x10cde7828 - <rustc_middle[6b51fbc1467208f7]::ty::context::GlobalCtxt>::enter::<rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}::{closure#0}::{closure#3}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>
  42:        0x10cdaa760 - <rustc_interface[1589e896c9a48ab2]::interface::Compiler>::enter::<rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}::{closure#0}, core[8f94067186277a42]::result::Result<core[8f94067186277a42]::option::Option<rustc_interface[1589e896c9a48ab2]::queries::Linker>, rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>
  43:        0x10cde53f4 - rustc_span[1bac0d14ce0e9ad9]::set_source_map::<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_interface[1589e896c9a48ab2]::interface::run_compiler<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}>::{closure#0}::{closure#0}>
  44:        0x10cde6a70 - rustc_span[1bac0d14ce0e9ad9]::create_session_globals_then::<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_interface[1589e896c9a48ab2]::util::run_in_thread_pool_with_globals<rustc_interface[1589e896c9a48ab2]::interface::run_compiler<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}>::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#0}>
  45:        0x10ce057c4 - std[e09757a2c7ce6988]::sys_common::backtrace::__rust_begin_short_backtrace::<rustc_interface[1589e896c9a48ab2]::util::run_in_thread_with_globals<rustc_interface[1589e896c9a48ab2]::util::run_in_thread_pool_with_globals<rustc_interface[1589e896c9a48ab2]::interface::run_compiler<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}>::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>
  46:        0x10cdfbb78 - <<std[e09757a2c7ce6988]::thread::Builder>::spawn_unchecked_<rustc_interface[1589e896c9a48ab2]::util::run_in_thread_with_globals<rustc_interface[1589e896c9a48ab2]::util::run_in_thread_pool_with_globals<rustc_interface[1589e896c9a48ab2]::interface::run_compiler<core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>, rustc_driver_impl[dca98f68974adbed]::run_compiler::{closure#0}>::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#0}::{closure#0}, core[8f94067186277a42]::result::Result<(), rustc_span[1bac0d14ce0e9ad9]::ErrorGuaranteed>>::{closure#1} as core[8f94067186277a42]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
  47:        0x103a8500c - std::sys::pal::unix::thread::Thread::new::thread_start::hc285c3138ab3bdc5
  48:        0x1845fe034 - __pthread_joiner_wake


rustc version: 1.78.0-nightly (ee9c7c940 2024-02-14)
platform: aarch64-apple-darwin

query stack during panic:
#0 [hir_crate] getting the crate HIR
#1 [analysis] running analysis passes on this crate
end of query stack

I plan to delve into this in the near future. @rustbot claim

edit: no ice in rustc 1.78.0-nightly (bccb9bbb4 2024-02-16)

@bvanjoi
Copy link
Contributor

bvanjoi commented Feb 26, 2024

This issue encompasses two problems:

firstly

// rustc code.rs --edition=2018 
macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(a!()); // it will throw unresolved error
}

And it will resolved by #121589.

@bvanjoi
Copy link
Contributor

bvanjoi commented Feb 26, 2024

And secondly:

// rustc code.rs --edition=2015
macro_rules! wrap {
    () => {
        #[macro_export]
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }        
    };
}

wrap!();

use _a as a; 
//^ throw error contains `macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths`

fn main() {
    let a = crate::a!();
    format_args!("{:#?}", a);
}

I will delve into this case at a later point.

bors added a commit to rust-lang-ci/rust that referenced this issue Mar 5, 2024
try to resolve under eager expander

Fixes rust-lang#98291

I will attempt to clarify the root problem through several examples:

Firstly,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(_a!());
}
```

The above case will compile successfully because `_a` is defined after the `wrap` expaned, ensuring `_a` can be resolved without any issues.

And,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!("{}", a!());
}
```

The above example will also compile successfully because the `parse_args` in `expand_format_args_impl` will return a value `MacroInput { fmtstr: Expr::Lit::Str, args: [Expr::MacroCall]}`. Since the graph for `args` will be build lately, `a` will eventually be resolved.

However, in the case of:

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(a!());
}
```

The result of `parse_args` is `MacroInput {fmtstr: Expr::Lit::Macro, args: [] }`, we attempt to expand `fmtstr` **eagerly** within `expr_to_spanned_string`. Although we have recorded `(root, _a)` into resolutions, `use _a as a` is an indeterminate import, which will not try to resolve under the conditions of `expander.monotonic = false`.

Therefore, I've altered the strategy for resolving indeterminate imports, ensuring it will also resolve during eager expansion. This could be a significant change to the resolution infra. However, I think it's acceptable if the goal of avoiding resolution under eager expansion is to save time.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this issue Mar 12, 2024
delay expand macro bang when there has indeterminate path

Related rust-lang#98291

I will attempt to clarify the root problem through several examples:

Firstly,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(_a!());
}
```

The above case will compile successfully because `_a` is defined after the `wrap` expaned, ensuring `_a` can be resolved without any issues.

And,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!("{}", a!());
}
```

The above example will also compile successfully because the `parse_args` in `expand_format_args_impl` will return a value `MacroInput { fmtstr: Expr::Lit::Str, args: [Expr::MacroCall]}`. Since the graph for `args` will be build lately, `a` will eventually be resolved.

However, in the case of:

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(a!());
}
```

The result of `parse_args` is `MacroInput {fmtstr: Expr::Lit::Macro, args: [] }`, we attempt to expand `fmtstr` **eagerly** within `expr_to_spanned_string`. Although we have recorded `(root, _a)` into resolutions, `use _a as a` is an indeterminate import, which will not try to resolve under the conditions of `expander.monotonic = false`.

Therefore, I've altered the strategy for resolving indeterminate imports, ensuring it will also resolve during eager expansion. This could be a significant change to the resolution infra. However, I think it's acceptable if the goal of avoiding resolution under eager expansion is to save time.

r? `@petrochenkov`
bors added a commit to rust-lang-ci/rust that referenced this issue Mar 13, 2024
delay expand macro bang when there has indeterminate path

Related rust-lang#98291

I will attempt to clarify the root problem through several examples:

Firstly,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(_a!());
}
```

The above case will compile successfully because `_a` is defined after the `wrap` expaned, ensuring `_a` can be resolved without any issues.

And,

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!("{}", a!());
}
```

The above example will also compile successfully because the `parse_args` in `expand_format_args_impl` will return a value `MacroInput { fmtstr: Expr::Lit::Str, args: [Expr::MacroCall]}`. Since the graph for `args` will be build lately, `a` will eventually be resolved.

However, in the case of:

```rs
// rustc code.rs --edition=2018

macro_rules! wrap {
    () => {
        macro_rules! _a {
            () => {
                "Hello world"
            };
        }
    };
}

wrap!();

use _a as a;

fn main() {
    format_args!(a!());
}
```

The result of `parse_args` is `MacroInput {fmtstr: Expr::Lit::Macro, args: [] }`, we attempt to expand `fmtstr` **eagerly** within `expr_to_spanned_string`. Although we have recorded `(root, _a)` into resolutions, `use _a as a` is an indeterminate import, which will not try to resolve under the conditions of `expander.monotonic = false`.

Therefore, I've altered the strategy for resolving indeterminate imports, ensuring it will also resolve during eager expansion. This could be a significant change to the resolution infra. However, I think it's acceptable if the goal of avoiding resolution under eager expansion is to save time.

r? `@petrochenkov`
@nyurik
Copy link
Contributor

nyurik commented Feb 21, 2025

I ran into this issue when I tried to add a new #[clippy::format_args] to a large project's logging macros. Reproducible with this on Rust v1.85. I have no idea how to even approach it, let alone the reason for this.

#[clippy::format_args]
#[macro_export]
macro_rules! my_log {
    ($($t:tt)*) => ($crate::my_log_impl(format_args!($($t)*)))
}

pub fn my_log_impl(args: core::fmt::Arguments) {
    println!("{}", args);
}

fn main() {
    sub::run();
}

mod sub {
    use crate::my_log;

    pub fn run() {
        my_log!("Hello, world!");
    }
}
error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
  --> src/main.rs:16:9
   |
16 |     use crate::my_log;
   |         ^^^^^^^^^^^^^
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
  --> src/main.rs:3:1
   |
3  | / macro_rules! my_log {
4  | |     ($($t:tt)*) => ($crate::my_log_impl(format_args!($($t)*)))
5  | | }
   | |_^
   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default

@nyurik
Copy link
Contributor

nyurik commented Feb 23, 2025

CC: @bvanjoi and @petrochenkov I saw you had a relevant PR #121589, but it seems the bug is still there. Moreover, it is now more visible because v1.85 introduced an ability for Clippy to lint code when the 3rd party crates include an attribute on a macro. I tried adding the new attribute to both stdlib and 3rd party crates, and only the log crate worked ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-resolve Area: Name/path resolution done by `rustc_resolve` specifically C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants