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

elided_lifetime_in_path triggers for the format! macro #48385

Closed
nikomatsakis opened this issue Feb 20, 2018 · 15 comments
Closed

elided_lifetime_in_path triggers for the format! macro #48385

nikomatsakis opened this issue Feb 20, 2018 · 15 comments
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

I was trying to use deny(elided_lifetime_in_path) and encountered the problem that this doesn't work:

#![feature(nll)]
#![deny(elided_lifetime_in_path)]

fn main() {
    format!("foo {}", 22)
}

I get

error: hidden lifetime parameters are deprecated, try `Foo<'_>`
 --> src/main.rs:5:5
  |
5 |     format!("foo {}", 22)
  |     ^^^^^^^^^^^^^^^^^^^^^
  |
note: lint level defined here
 --> src/main.rs:2:9
  |
2 | #![deny(elided_lifetime_in_path)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^
  = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

I suppose the easiest fix is to fix the format! expansion, but maybe better to suppress this warning for macros outside of the current crate? Feels like a more general problem.

@nikomatsakis nikomatsakis added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Feb 20, 2018
@nikomatsakis
Copy link
Contributor Author

cc @Dylan-DPC

@withoutboats
Copy link
Contributor

Feels like a more general problem.

I think the more general problem is that lints should be hygienic - we should only check them against ast nodes from this code, not those generated by a macro.

@shepmaster
Copy link
Member

we should only check them against ast nodes from this code

I've seen someone bit by something similar. They had a deny(unsafe) but a crate's macro ended up expanding to an unsafe block. IIRC, they fixed the library to add an allow on the block inside the macro.

So +1 for this kind of fix.

@durka
Copy link
Contributor

durka commented Feb 20, 2018

That won't help with forbid.

@Dylan-DPC-zz
Copy link

Any pointers on how to suppress this warning for macros outside of the current crate?

@durka
Copy link
Contributor

durka commented Feb 21, 2018

Clippy has a function.

@nikomatsakis
Copy link
Contributor Author

It does feel wrong to do this on a lint-by-lint basis, though, right? Maybe as part of struct_lint_level?

pub fn struct_lint_level<'a>(sess: &'a Session,
lint: &'static Lint,
level: Level,
src: LintSource,
span: Option<MultiSpan>,
msg: &str)
-> DiagnosticBuilder<'a>
{
let mut err = match (level, span) {
(Level::Allow, _) => return sess.diagnostic().struct_dummy(),
(Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
(Level::Warn, None) => sess.struct_warn(msg),
(Level::Deny, Some(span)) |
(Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
(Level::Deny, None) |
(Level::Forbid, None) => sess.struct_err(msg),
};

We could e.g. return the "dummy" value for spans that are not in the current crate:

(Level::Allow, _) => return sess.diagnostic().struct_dummy(),

@Manishearth
Copy link
Member

Manishearth commented Feb 23, 2018

It does feel wrong to do this on a lint-by-lint basis, though, right? Maybe as part of struct_lint_level?

It's not that simple, though. The node being linted may be outside of a macro, but it may contain macroy things that affect the lint. The correct way to handle this is to identify all the "important" nodes and do a macro check.

(Also: All currently supported ways of doing a macro check will not lint stuff like some_macro!(some.code.that.hits.the.lint), which isn't an uncommon breed of macro.)

@nikomatsakis
Copy link
Contributor Author

@Manishearth

The correct way to handle this is to identify all the "important" nodes and do a macro check.

So actually struct_lint_level is probably not the right place. Rather, lint_level_at_node:

pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId)
-> (lint::Level, lint::LintSource)
{
// Right now we insert a `with_ignore` node in the dep graph here to
// ignore the fact that `lint_levels` below depends on the entire crate.
// For now this'll prevent false positives of recompiling too much when
// anything changes.
//
// Once red/green incremental compilation lands we should be able to
// remove this because while the crate changes often the lint level map
// will change rarely.
self.dep_graph.with_ignore(|| {
let sets = self.lint_levels(LOCAL_CRATE);
loop {
let hir_id = self.hir.definitions().node_to_hir_id(id);
if let Some(pair) = sets.level_and_source(lint, hir_id) {
return pair
}
let next = self.hir.get_parent_node(id);
if next == id {
bug!("lint traversal reached the root of the crate");
}
id = next;
}
})
}

That is, this seems like an identical problem to deciding whether the lint is enabled. We're basically talking about adding some measure of hygiene to that check, right?

(Also, I'm totally willing to be believe we should just work around this for now, and defer any more general changes to be done as part of a hygiene-overhaul-sort-of-thing.)

@nikomatsakis
Copy link
Contributor Author

(One annoying problem: that fn does not presently have a span.)

@Manishearth
Copy link
Member

Manishearth commented Feb 23, 2018

It's almost identical to that problem, and I think we can get away with that approximation for now.

I can think of counterexamples but it just makes the lints slightly overconservative so nbd.

However, bear in mind that we may not want this at all for future compat lints (we already catalog these so we can special case this).

@nikomatsakis
Copy link
Contributor Author

@Manishearth

However, bear in mind that we may not want this at all for future compat lints (we already catalog these so we can special case this).

Interesting point. Probably we don't, yes. =) (The story around future compatibility and dependencies is sort of complicated, I think, but see also #34596)

@Manishearth
Copy link
Member

Issue for adding macro checks to lints at #48855

@XAMPPRocky XAMPPRocky added C-enhancement Category: An issue proposing an enhancement or a PR with one. A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. labels May 7, 2018
@reuvenpo
Copy link

reuvenpo commented Jul 3, 2018

This issue is also related to this topic: #51903.
Is this prioritised in any way? Seems like this had been known for a while now, and it's a shame because i would like to use this lint in my code.

@zackmdavis
Copy link
Member

This is now fixed (lint was rewritten in #52069).

zmd@ReflectiveCoherence:~/Code/Misc$ cat 48385.rs 
#![feature(nll)]
#![deny(elided_lifetimes_in_paths)]

fn main() {
    format!("foo {}", 22);
}
zmd@ReflectiveCoherence:~/Code/Misc$ rustc +nightly --version
rustc 1.31.0-nightly (e7f5d4805 2018-10-18)
zmd@ReflectiveCoherence:~/Code/Misc$ rustc +nightly 48385.rs 
zmd@ReflectiveCoherence:~/Code/Misc$ echo $?
0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: Lints (warnings about flaws in source code) such as unused_mut. C-enhancement Category: An issue proposing an enhancement or a PR with one. 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

9 participants