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

Stability lint for nested macros #17508

Merged
merged 1 commit into from
Oct 21, 2014
Merged

Stability lint for nested macros #17508

merged 1 commit into from
Oct 21, 2014

Conversation

elinorbgr
Copy link
Contributor

Finishes the job of #17286.

Now the stability lint will successfully detect patterns such as:

first_macro!(second_macro!(deprecated_function()));
macro_rules! foo (
    ($e: expr) => (bar!($e))
)
foo!(deprected_function());

and

println!("{}", deprecated_function());

even with more levels of nesting, such as

println!("{}", foo!(bar!(deprecated_function())));

@rust-highfive
Copy link
Collaborator

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @aturon (or someone else) soon.

@aturon
Copy link
Member

aturon commented Sep 24, 2014

@vberger Thanks so much for doing this!

I don't know the macro internals well enough to do more than rubber-stamp this; I'm going to ask someone who does to review.

@aturon
Copy link
Member

aturon commented Sep 24, 2014

r? @pnkfelix

} else {
false
// was this code from the current macro arguments ?
skip = !( e.span.lo > info.call_site.lo && e.span.hi < info.call_site.hi );
Copy link
Member

Choose a reason for hiding this comment

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

hmm. do we use this sort of span comparison logic elsewhere in a significant manner?

I ask because I spent some time investigating our span calculations and found that they are not always sound

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pnkfelix I must admit I assumed they where correct (as that's what is used to align the ^~~~~ in the warning message).

The only situations where I encountered some that where not reliable was when dealing with compiler built-ins, that's pretty much why I skip them.

I couldn't find any other way to check whether an expression actually was from the macro arguments or was created by the macro. I couldn't find informations about macro expansion anywhere else.
If you know where I could look to seek more reliable data, I'd be glad to use it.

@aturon
Copy link
Member

aturon commented Oct 6, 2014

@pnkfelix Ping. Would be good to move forward with this.

@aturon
Copy link
Member

aturon commented Oct 6, 2014

@huonw Do you know the relevant macro stuff enough to properly review this?

@@ -1470,26 +1470,31 @@ impl LintPass for Stability {
}

fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
// skip if `e` is not from macro arguments
let skip = cx.tcx.sess.codemap().with_expn_info(e.span.expn_id, |expninfo| {
// firt, check if the given expression was generated by a macro or not
Copy link
Member

Choose a reason for hiding this comment

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

s/firt/fisrt/

Copy link
Member

Choose a reason for hiding this comment

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

Haha, whoops: first.

@huonw
Copy link
Member

huonw commented Oct 7, 2014

(Just checking my understanding.)

Would it be accurate to describe this as:

  • traverse to the top-most* macro in the macro expansion stack,
  • check if the expression is in the arguments of that macro (that is, checks that the span of the original expression is contained within the span of that top macro invocation)
  • (attempt to) emit a stability warning if it is?

*I understand that it is checking the spans at each step, but it seems that overwrites skip for each layer.


If someone wishes to experiment with the macro stack to understand better, I used a lint like the following to check what was going on:

// span-lint.rs
#![feature(phase, plugin_registrar)]
#![crate_type = "dylib"]

extern crate syntax;
#[phase(plugin, link)] extern crate rustc;

use syntax::ast;
use rustc::plugin::Registry;
use rustc::lint::{Context, LintArray, LintPass};
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box SpanLint);
}

declare_lint! { SPAN_LINT, Warn, "..." }

struct SpanLint;

impl LintPass for SpanLint {
    fn get_lints(&self) -> LintArray {
        lint_array!(SPAN_LINT)
    }

    fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
        let mut sp = e.span;
        let mut stop = false;
        cx.tcx.sess.span_warn(sp, "starts here");
        while !stop {
            cx.tcx.sess.codemap().with_expn_info(sp.expn_id, |expn_info| {
                match expn_info {
                    None => stop = true,
                    Some(ref info) => {
                        sp = info.call_site;
                        cx.tcx.sess.span_note(sp, "continues");
                    }
                }
            })
        }
    }
}
#![feature(phase, macro_rules)]
#[phase(plugin)]
extern crate "span-lint" as _lint;

macro_rules! bar {
    ($e: expr) => { $e }
}

macro_rules! foo {
    ($e: expr) => { bar!($e) };
    () => { 1u }
}

fn main() {
    foo!(1u);
    foo!();
}
test-span-lint.rs:15:10: 15:12 warning: starts here
test-span-lint.rs:15     foo!(1u);
                              ^~
test-span-lint.rs:5:1: 7:2 note: in expansion of bar!
test-span-lint.rs:10:21: 10:29 note: expansion site
test-span-lint.rs:9:1: 12:2 note: in expansion of foo!
test-span-lint.rs:15:5: 15:14 note: expansion site
test-span-lint.rs:10:21: 10:29 note: continues
test-span-lint.rs:10     ($e: expr) => { bar!($e) };
                                         ^~~~~~~~
test-span-lint.rs:9:1: 12:2 note: in expansion of foo!
test-span-lint.rs:15:5: 15:14 note: expansion site
test-span-lint.rs:15:5: 15:14 note: continues
test-span-lint.rs:15     foo!(1u);
                         ^~~~~~~~~
test-span-lint.rs:11:13: 11:15 warning: starts here
test-span-lint.rs:11     () => { 1u }
                                 ^~
test-span-lint.rs:9:1: 12:2 note: in expansion of foo!
test-span-lint.rs:16:5: 16:12 note: expansion site
test-span-lint.rs:16:5: 16:12 note: continues
test-span-lint.rs:16     foo!();
                         ^~~~~~~

(I don't know how to disable the conventional stack trace printing, so just focus on the starts here and continues lines.)

@elinorbgr
Copy link
Contributor Author

@huonw I just corrected including your comments.

And yes, this is exactly how it works. This structure of over-writing the is_internal (former skip) variable each turn was a mean to make the whole thing more compact (to avoid having two match { } blocks), but I can change it to something more explicit if preferred.

@elinorbgr
Copy link
Contributor Author

@huonw @pnkfelix So finally, is it acceptable of use the spans to discriminate expressions from the arguments of a macro, or not ?

@pnkfelix
Copy link
Member

assigning self to review. (I'm not sure I'd be comfortable with using the spans, though of course lints are subject to less stringent correctness conditions than e.g. type-check analyses...)

@pnkfelix pnkfelix self-assigned this Oct 14, 2014
@huonw
Copy link
Member

huonw commented Oct 14, 2014

It's not obvious to me that there is a solution without using the spans; certainly not one as easy as using the spans. (Maybe I'm just not being imaginative enough...)

@aturon
Copy link
Member

aturon commented Oct 17, 2014

Would really like to get this merged. Should I just rubber-stamp it at this point? @huonw @pnkfelix

@huonw
Copy link
Member

huonw commented Oct 17, 2014

I'm personally happy with it (enough to r+), but @pnkfelix may have some desired tweaks.

@pnkfelix
Copy link
Member

I'm going to review this today, in part because I want to learn how this technique (a la #17286 ) works well enough to apply it to #18102

@elinorbgr
Copy link
Contributor Author

Oops, I lost my second commit (fixing deprecated calls in the libs) while rebasing. I'll make it back.

@elinorbgr
Copy link
Contributor Author

It seems that all changes implied by that commit are no longer relevant. I'm thus good for review @pnkfelix .

bors added a commit that referenced this pull request Oct 21, 2014
… r=pnkfelix

Finishes the job of #17286.

Now the stability lint will successfully detect patterns such as:
```
first_macro!(second_macro!(deprecated_function()));
```
```
macro_rules! foo (
    ($e: expr) => (bar!($e))
)
foo!(deprected_function());
```
and
```
println!("{}", deprecated_function());
```
even with more levels of nesting, such as
```
println!("{}", foo!(bar!(deprecated_function())));
```
@bors bors closed this Oct 21, 2014
@bors bors merged commit dd55c80 into rust-lang:master Oct 21, 2014
@elinorbgr elinorbgr deleted the stability_lint_for_nested_macros branch November 6, 2014 13:32
lnicola pushed a commit to lnicola/rust that referenced this pull request Jul 11, 2024
feat: Add landing/faq walkthrough pages

This is a basic implementation of a landing and FAQ page; I've included the bare-bones information as well as a [recommended section on inlay hints](https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer/topic/Landing.20Page/near/446135321).

I've also added `rust-analyzer: Open Walkthrough` and `rust-analyzer: Open FAQ` commands for ease of access.

I am hoping to create a small list of FAQ to include that might be useful as well as any other information I may have missed in the landing page. Feel free to share any suggestions!

![landing/faq page demo](https://github.com/rust-lang/rust-analyzer/assets/100006388/4644e4f0-4555-4b29-83c1-b048084ad63d)

cc rust-lang#13351
lnicola pushed a commit to lnicola/rust that referenced this pull request Jul 28, 2024
internal: remove rust-analyzer.openFAQ

Removed no longer functional `rust-analyzer.openFAQ` command created in rust-lang#17508
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants