Skip to content
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

Parse unsafe attributes #124214

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

carbotaniuman
Copy link
Contributor

Initial parse implementation for #123757

This is the initial work to parse unsafe attributes, which is represented as an extra unsafety field in MetaItem and AttrItem. There's two areas in the code where it appears that parsing is done manually and not using the parser stuff, and I'm not sure how I'm supposed to thread the change there.

@rustbot
Copy link
Collaborator

rustbot commented Apr 21, 2024

r? @michaelwoerister

rustbot has assigned @michaelwoerister.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 21, 2024
@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Apr 21, 2024

☔ The latest upstream changes (presumably #124208) made this pull request unmergeable. Please resolve the merge conflicts.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Apr 25, 2024

☔ The latest upstream changes (presumably #124360) made this pull request unmergeable. Please resolve the merge conflicts.

@@ -628,6 +628,7 @@ declare_features! (
/// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
/// Allows unsized fn parameters.
(unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doc comment needs an update too.

@michaelwoerister
Copy link
Member

Thanks for the PR, @carbotaniuman!

Would you mind also adding a test case where using unsafe(..) works as expected and one where it is used in a nested context, like #[cfg_attr(foo, unsafe(no_mangle)]?

@carbotaniuman carbotaniuman force-pushed the parse_unsafe_attrs branch 2 times, most recently from c91ab4f to eb16919 Compare April 25, 2024 16:39
@bors
Copy link
Contributor

bors commented Apr 27, 2024

☔ The latest upstream changes (presumably #124424) made this pull request unmergeable. Please resolve the merge conflicts.

@carbotaniuman
Copy link
Contributor Author

I've added stuff to handle the $meta matcher in macro_rules!. I'm not sure if it's needed, but it's technically breaking, and RFC 3531 suggests I do.

@@ -911,7 +912,7 @@ impl NonterminalKind {
sym::ident => NonterminalKind::Ident,
sym::lifetime => NonterminalKind::Lifetime,
sym::literal => NonterminalKind::Literal,
sym::meta => NonterminalKind::Meta,
sym::meta => NonterminalKind::Meta2021,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually needed? The grammar doesn't change, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure...

https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=5ccbe0db996ad629df3df4dc2119e2cd

#[cfg_attr(not(debug), unsafe(Foo))]
struct Foo;

The above is a parse error right now as it expects a path and not a keyword. There were 2 implementations strategies I considered, one of which was defining a macro unsafe that created the Attribute with the proper unsafety, but given that I would still need syntax changes (to deal with the unsafe), I opted to instead change the core AttrItem itself to have an unsafety field. So I'm not really sure if a) this is the right way of doing things and b) if I need to make the macro changes.

ast::Unsafe::No
};

let path = this.parse_path(PathStyle::Mod)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this to result in a slightly weird error message when doing something like #[unsafe(unsafe(no_mangle))]. Can we add a test case for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error: expected identifier, found keyword `unsafe`
  --> /home/quydx/code/rust/tests/ui/attributes/unsafe/double-unsafe-in-attribute.rs:1:10
   |
LL | #[unsafe(unsafe(no_mangle))]
   |          ^^^^^^ expected identifier, found keyword
   |
help: escape `unsafe` to use it as an identifier
   |
LL | #[unsafe(r#unsafe(no_mangle))]
   |          ++

error: cannot find attribute `r#unsafe` in this scope
  --> /home/quydx/code/rust/tests/ui/attributes/unsafe/double-unsafe-in-attribute.rs:1:10
   |
LL | #[unsafe(unsafe(no_mangle))]
   |          ^^^^^^

The error is basically just what we have now. I can probably add a note saying that unsafe(...) doesn't nest.

@@ -170,6 +175,7 @@ impl<'a> Parser<'a> {
NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
}
NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(true)?)),
NonterminalKind::Meta2021 => NtMeta(P(self.parse_attr_item_no_unsafe(true)?)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I'm not sure this is necessary because using unsafe(...) currently fails to parse (see playground example). So I think this should fall under the following paragraph from RFC 3531:

In cases where we’re adding new syntax and updating the grammar to include that new syntax, if we can update the corresponding fragment specifier simultaneously to match the new grammar in such a way that we do not risk changing the behavior of existing macros (i.e., because the new syntax previously would have failed parsing), then we will do that so as to prevent or minimize divergence between the fragment specifier and the new grammar.

I.e. the question is: Can the addition of unsafe(..) change the behavior of any currently valid macros / macro invocations?

@michaelwoerister
Copy link
Member

I think we need some expert input. There are two main questions:

  • The PR's current implementation strategy for unsafe attributes is to add an unsafety field to AttrItem and MetaItem and handled that during parsing. I.e. #[unsafe(Something)] will end up as a flat Something AttrItem as opposed to an unsafe AttrItem with Something nested as an argument. Given that the RFC says that unsafe attributes cannot be nested or complex, that implementation strategy makes sense to me. But I'm no parsing/macros expert so it would be good to get additional opinions here.

  • The PR currently introduces a new meta_2021 fragment specifier to account for the unsafe attributes changes (see RFC 3531 - Macro matcher fragment specifiers edition policy). However, I think that is not necessary since #[unsafe(something)] does not currently parse (see playground example). Therefore starting to allow it for the existing meta fragment specifier should not be a breaking change and does not need to happen on an edition boundary. Does this reasoning overlook something?

@rustbot ping parser

@rustbot
Copy link
Collaborator

rustbot commented May 2, 2024

Error: This team (parser) cannot be pinged via this command; it may need to be added to triagebot.toml on the default branch.

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #t-infra on Zulip.

@michaelwoerister
Copy link
Member

It looks like rustbot does not allow pinging adhoc groups, so pinging manually regarding the questions in the comment above: @compiler-errors @davidtwco @estebank @nnethercote @petrochenkov @spastorino

@petrochenkov
Copy link
Contributor

The PR's current implementation strategy for unsafe attributes is to add an unsafety field to AttrItem and MetaItem and handled that during parsing. I.e. #[unsafe(Something)] will end up as a flat Something AttrItem as opposed to an unsafe AttrItem with Something nested as an argument.

This is the right strategy.
It would be more clear if the syntax was different, like #[unsafe my_attr].
The confusing parenthesized syntax was selected in the end, but it doesn't change the semantics.

@petrochenkov
Copy link
Contributor

Macro matcher fragment specifiers edition policy](https://rust-lang.github.io/rfcs/3531-macro-fragment-policy.html)). However, I think that is not necessary since #[unsafe(something)] does not currently parse (see playground example).

It would be good if unsafe could fit into the existing meta matcher.

There may be some issues with ambiguities between macro arms in cases similar to

macro_rules! m {
    (unsafe) => { 1 }
    ($meta:meta) => { 2 }
}

m!(unsafe(no_mangle));

This needs some testing.

@michaelwoerister
Copy link
Member

This is the right strategy.

Thanks for the feedback!

It would be more clear if the syntax was different, like #[unsafe my_attr].
The confusing parenthesized syntax was selected in the end, but it doesn't change the semantics.

Yes, I read through the RFC discussion thread today. I'm going to stay neutral regarding the choice 🙂
From a grammar point of view #[unsafe my_attr] would indeed be clearer.

@michaelwoerister
Copy link
Member

It would be good if unsafe could fit into the existing meta matcher.

Let's try to make that work then.

There may be some issues with ambiguities between macro arms in cases similar to

macro_rules! m {
    (unsafe) => { 1 }
    ($meta:meta) => { 2 }
}

m!(unsafe(no_mangle));

This needs some testing.

To clarify, the above test case would be an example where the current and the new meta matcher could give different results?

Do you mean a case like the following where currently :meta does not match unsafe(no_mangle), so we get the second arm, but with the new behavior we would get the first one (playground)?:

fn main() {
    macro_rules! foo {
        ($l:meta) => { 1 };
        (unsafe($x:ident)) => { 2 };
    }

    let x = foo!(unsafe(no_mangle));
    println!("{x}");
}

@carbotaniuman
Copy link
Contributor Author

Yeah, that foo macro is the main one I'm worried about. I think you could get away with it with some sort of migration lint, but I'm really not sure.

@michaelwoerister
Copy link
Member

@carbotaniuman, can you bring this PR in a state where we don't introduce a separate meta_2021 matcher and just modify the existing meta matcher? Then we can do a crater run to see what the impact is.

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 7, 2024
@carbotaniuman
Copy link
Contributor Author

Alright, I've reverted those commits.

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 8, 2024
@michaelwoerister
Copy link
Member

Thanks, @carbotaniuman!

Let's do a try build for the crater run.
@bors try

I guess we'll need a build-and-test run since the difference in parsing does not necessarily result in a compile time error.

bors added a commit to rust-lang-ci/rust that referenced this pull request May 8, 2024
…<try>

Parse unsafe attributes

Initial parse implementation for rust-lang#123757

This is the initial work to parse unsafe attributes, which is represented as an extra `unsafety` field in `MetaItem` and `AttrItem`. There's two areas in the code where it appears that parsing is done manually and not using the parser stuff, and I'm not sure how I'm supposed to thread the change there.
@bors
Copy link
Contributor

bors commented May 8, 2024

⌛ Trying commit aadc436 with merge 54bfda8...

@michaelwoerister
Copy link
Member

A code search on github does not yield anything that looks problematic:
/#\[unsafe\(.*\)\]/ language:Rust
/#\[cfg_attr\(.*,.*unsafe\(.*\)\)\]/ language:Rust

@bors
Copy link
Contributor

bors commented May 8, 2024

☀️ Try build successful - checks-actions
Build commit: 54bfda8 (54bfda8e7e7745c74b12d95d7a6cd614e83f888c)

@michaelwoerister
Copy link
Member

@craterbot run mode=build-and-test

@craterbot
Copy link
Collaborator

👌 Experiment pr-124214 created and queued.
🤖 Automatically detected try build 54bfda8
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 8, 2024
@traviscross
Copy link
Contributor

@rustbot labels +I-lang-nominated

Let's nominate to discuss and confirm that the only attributes that need to be marked as unsafe are:

  • no_mangle
  • link_section
  • export_name

There's been discussion about link and link_ordinal also.

cc @RalfJung

@rustbot rustbot added the I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. label May 14, 2024
@RalfJung
Copy link
Member

This is the best list I know. But I honestly don't have a good overview of which attributes we even have for controlling linker behavior, let alone which of them are unsafe.

Cc @bjorn3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-lang-nominated The issue / PR has been nominated for discussion during a lang team meeting. S-waiting-on-crater Status: Waiting on a crater run to be completed. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants