Skip to content

Regression in do_not_recommend span placement in macro-generated code #156759

@dtolnay

Description

@dtolnay

This bisects to #156676, which was designed to solve #156475. The original issue involves code that is not macro-generated. I believe heuristics may need to be adjusted for the case of macro-generated code. It is common that macros use diagnostic attributes and assorted tricks to place custom error messages at some intentional location within the macro's input.

The following is minimized from https://github.com/dtolnay/cxx. It is designed to produce an error if and only if Unpin is not implemented for some type, in this case Arg.

# Cargo.toml

[package]
name = "repro"
edition = "2024"
publish = false

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1"
quote = "1"
// src/main.rs

pub struct Arg(std::marker::PhantomPinned);

#[repro::repro]
fn f(arg: &mut Arg);

fn main() {}
// src/lib.rs

use proc_macro::{TokenStream, TokenTree};

#[proc_macro_attribute]
pub fn repro(_args: TokenStream, input: TokenStream) -> TokenStream {
    // Parse input that looks like `fn f(arg: &mut Arg);`
    let mut input = input.into_iter();
    assert_eq!(input.next().unwrap().to_string(), "fn");
    assert_eq!(input.next().unwrap().to_string(), "f");
    let TokenTree::Group(group) = input.next().unwrap() else {
        unreachable!()
    };
    let mut input = group.stream().into_iter();
    assert_eq!(input.next().unwrap().to_string(), "arg");
    assert_eq!(input.next().unwrap().to_string(), ":");
    let arg: TokenStream = input.collect();
    let arg: proc_macro2::TokenStream = arg.into();

    // Emit output:
    TokenStream::from(quote::quote! {
        const _: fn() = {
            #[diagnostic::on_unimplemented(
                message = "mutable reference to C++ type requires a pin -- use Pin<&mut Arg>",
                label = "use `Pin<&mut Arg>`"
            )]
            trait ReferenceToUnpin_Arg {
                fn check_unpin() {}
            }
            #[diagnostic::do_not_recommend]
            impl<
                'a,
                T: ?::core::marker::Sized + ::core::marker::Unpin,
            > ReferenceToUnpin_Arg for &'a mut T {}
            <#arg as ReferenceToUnpin_Arg>::check_unpin
        };
    })
}

Before #156676:

error[E0277]: mutable reference to C++ type requires a pin -- use Pin<&mut Arg>
 --> src/main.rs:6:11
  |
6 | fn f(arg: &mut Arg);
  |           ^^^^^^^^ use `Pin<&mut Arg>`
  |
  = help: the trait `ReferenceToUnpin_Arg` is not implemented for `&mut Arg`

After #156676:

error[E0277]: mutable reference to C++ type requires a pin -- use Pin<&mut Arg>
 --> src/main.rs:5:1
  |
5 | #[repro::repro]
  | ^^^^^^^^^^^^^^^ use `Pin<&mut Arg>`
  |
  = help: the trait `ReferenceToUnpin_Arg` is not implemented for `&mut Arg`
  = note: this error originates in the attribute macro `repro::repro` (in Nightly builds, run with -Z macro-backtrace for more info)

@qaijuang @chenyukang

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-nightlyPerformance or correctness regression from stable to nightly.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions