Skip to content

Commit

Permalink
in which we decline to suggest the anonymous lifetime in declarations
Browse files Browse the repository at this point in the history
The elided-lifetimes-in-path lint (part of our suite of Rust 2018
idiom lints which we are hoping to promote to Warn status) was firing
with an illegal suggestion to write an anonymous lifetime in a
struct/item declaration (where we don't allow it). The linting code
was already deciding whether to act on the basis of a `ParamMode`
enum, indicating whether the present path-segment was part of an
expression, or anywhere else. The present case seemed to be part of
the "anywhere else", and yet meriting different rules as far as the
lint was concerned, so it seemed expedient to introduce a new enum
member. We yank out a `TyKind::Path` arm into its own method so that
we can call it with our new `ParamMode` specifically when lowering
struct fields. (The alternative strategy of changing the signature of
`lower_ty` to take a `ParamMode` would be inelegant given that most of
the `TyKind` match arm bodies therein don't concern themselves with
`ParamMode`.)

Resolves rust-lang#61124.
  • Loading branch information
zackmdavis committed Jun 14, 2019
1 parent cdd7437 commit 7a3184a
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 8 deletions.
41 changes: 33 additions & 8 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ pub fn lower_crate(
enum ParamMode {
/// Any path in a type context.
Explicit,
/// Path in a type definition, where the anonymous lifetime `'_` is not allowed.
ExplicitNamed,
/// The `module::Type` in `module::Type::method` in an expression.
Optional,
}
Expand Down Expand Up @@ -1489,6 +1491,23 @@ impl<'a> LoweringContext<'a> {
P(self.lower_ty_direct(t, itctx))
}

fn lower_path_ty(
&mut self,
t: &Ty,
qself: &Option<QSelf>,
path: &Path,
param_mode: ParamMode,
itctx: ImplTraitContext<'_>
) -> hir::Ty {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
ty
}

fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::Ty {
let kind = match t.node {
TyKind::Infer => hir::TyKind::Infer,
Expand Down Expand Up @@ -1534,13 +1553,7 @@ impl<'a> LoweringContext<'a> {
return self.lower_ty_direct(ty, itctx);
}
TyKind::Path(ref qself, ref path) => {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
let ty = self.ty_path(id, t.span, qpath);
if let hir::TyKind::TraitObject(..) = ty.node {
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
}
return ty;
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
}
TyKind::ImplicitSelf => {
let res = self.expect_full_res(t.id);
Expand Down Expand Up @@ -3086,6 +3099,18 @@ impl<'a> LoweringContext<'a> {
}

fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField {
let ty = if let TyKind::Path(ref qself, ref path) = f.ty.node {
let t = self.lower_path_ty(
&f.ty,
qself,
path,
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
ImplTraitContext::disallowed()
);
P(t)
} else {
self.lower_ty(&f.ty, ImplTraitContext::disallowed())
};
hir::StructField {
span: f.span,
hir_id: self.lower_node_id(f.id),
Expand All @@ -3095,7 +3120,7 @@ impl<'a> LoweringContext<'a> {
None => Ident::new(sym::integer(index), f.span),
},
vis: self.lower_visibility(&f.vis, None),
ty: self.lower_ty(&f.ty, ImplTraitContext::disallowed()),
ty,
attrs: self.lower_attrs(&f.attrs),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![deny(elided_lifetimes_in_paths)]

// Previously, the elided-lifetimes-in-path lint would fire, but we don't want
// that, because `'_` isn't legal in struct declarations.

struct Betrayal<'a> { x: &'a u8 }

struct Heartbreak(Betrayal); //~ ERROR missing lifetime specifier

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0106]: missing lifetime specifier
--> $DIR/issue-61124-anon-lifetime-in-struct-declaration.rs:8:19
|
LL | struct Heartbreak(Betrayal);
| ^^^^^^^^ expected lifetime parameter

error: aborting due to previous error

For more information about this error, try `rustc --explain E0106`.

0 comments on commit 7a3184a

Please sign in to comment.