Auto merge of #97795 - Dylan-DPC:rollup-dxilagr, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #97312 (Compute lifetimes in scope at diagnostic time) - #97495 (Add E0788 for improper #[no_coverage] usage) - #97579 (Avoid creating `SmallVec`s in `global_llvm_features`) - #97767 (interpret: do not claim UB until we looked more into variadic functions) - #97787 (E0432: rust 2018 -> rust 2018 or later in --explain message) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
357bc27904
@ -313,6 +313,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'hir TypeBinding<'hir>) {
|
||||
self.insert(type_binding.span, type_binding.hir_id, Node::TypeBinding(type_binding));
|
||||
self.with_parent(type_binding.hir_id, |this| {
|
||||
intravisit::walk_assoc_type_binding(this, type_binding)
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
|
||||
// Do not visit the duplicate information in TraitItemRef. We want to
|
||||
// map the actual nodes, not the duplicate ones in the *Ref.
|
||||
|
@ -218,15 +218,17 @@ pub fn check_tied_features(
|
||||
sess: &Session,
|
||||
features: &FxHashMap<&str, bool>,
|
||||
) -> Option<&'static [&'static str]> {
|
||||
for tied in tied_target_features(sess) {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
if !features.is_empty() {
|
||||
for tied in tied_target_features(sess) {
|
||||
// Tied features must be set to the same value, or not set at all
|
||||
let mut tied_iter = tied.iter();
|
||||
let enabled = features.get(tied_iter.next().unwrap());
|
||||
if tied_iter.any(|f| enabled != features.get(f)) {
|
||||
return Some(tied);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
return None;
|
||||
}
|
||||
|
||||
// Used to generate cfg variables and apply features
|
||||
@ -440,6 +442,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
|
||||
// -Ctarget-features
|
||||
let supported_features = supported_target_features(sess);
|
||||
let mut featsmap = FxHashMap::default();
|
||||
let feats = sess
|
||||
.opts
|
||||
.cg
|
||||
@ -485,35 +488,36 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
Some((enable_disable, feature))
|
||||
})
|
||||
.collect::<SmallVec<[(char, &str); 8]>>();
|
||||
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
let featmap = feats.iter().map(|&(flag, feat)| (feat, flag == '+')).collect();
|
||||
if let Some(f) = check_tied_features(sess, &featmap) {
|
||||
sess.err(&format!(
|
||||
"target features {} must all be enabled or disabled together",
|
||||
f.join(", ")
|
||||
));
|
||||
}
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// rustc-specific features do not get passed down to LLVM…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
// ... otherwise though we run through `to_llvm_features` when
|
||||
// passing requests down to LLVM. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the LLVM name and the Rust name differ.
|
||||
Some(
|
||||
to_llvm_features(sess, feature)
|
||||
.into_iter()
|
||||
.map(move |f| format!("{}{}", enable_disable, f)),
|
||||
)
|
||||
})
|
||||
.flatten();
|
||||
features.extend(feats);
|
||||
|
||||
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
||||
sess.err(&format!(
|
||||
"target features {} must all be enabled or disabled together",
|
||||
f.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
features.extend(feats.into_iter().flat_map(|(enable_disable, feature)| {
|
||||
// rustc-specific features do not get passed down to LLVM…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return SmallVec::<[_; 2]>::new();
|
||||
}
|
||||
// ... otherwise though we run through `to_llvm_features` when
|
||||
// passing requests down to LLVM. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the LLVM name and the Rust name differ.
|
||||
to_llvm_features(sess, feature)
|
||||
.into_iter()
|
||||
.map(|f| format!("{}{}", enable_disable, f))
|
||||
.collect()
|
||||
}));
|
||||
features
|
||||
}
|
||||
|
||||
|
@ -353,12 +353,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// FIXME: for variadic support, do we have to somehow determine callee's extra_args?
|
||||
let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
|
||||
|
||||
if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic {
|
||||
throw_ub_format!(
|
||||
"calling a c-variadic function via a non-variadic call site, or vice versa"
|
||||
);
|
||||
}
|
||||
if callee_fn_abi.c_variadic {
|
||||
if callee_fn_abi.c_variadic || caller_fn_abi.c_variadic {
|
||||
throw_unsup_format!("calling a c-variadic function is not supported");
|
||||
}
|
||||
|
||||
|
@ -491,6 +491,7 @@ E0784: include_str!("./error_codes/E0784.md"),
|
||||
E0785: include_str!("./error_codes/E0785.md"),
|
||||
E0786: include_str!("./error_codes/E0786.md"),
|
||||
E0787: include_str!("./error_codes/E0787.md"),
|
||||
E0788: include_str!("./error_codes/E0788.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
@ -10,10 +10,10 @@ In Rust 2015, paths in `use` statements are relative to the crate root. To
|
||||
import items relative to the current and parent modules, use the `self::` and
|
||||
`super::` prefixes, respectively.
|
||||
|
||||
In Rust 2018, paths in `use` statements are relative to the current module
|
||||
unless they begin with the name of a crate or a literal `crate::`, in which
|
||||
case they start from the crate root. As in Rust 2015 code, the `self::` and
|
||||
`super::` prefixes refer to the current and parent modules respectively.
|
||||
In Rust 2018 or later, paths in `use` statements are relative to the current
|
||||
module unless they begin with the name of a crate or a literal `crate::`, in
|
||||
which case they start from the crate root. As in Rust 2015 code, the `self::`
|
||||
and `super::` prefixes refer to the current and parent modules respectively.
|
||||
|
||||
Also verify that you didn't misspell the import name and that the import exists
|
||||
in the module from where you tried to import it. Example:
|
||||
@ -38,8 +38,8 @@ use core::any;
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
In Rust 2018 the `extern crate` declaration is not required and you can instead
|
||||
just `use` it:
|
||||
Since Rust 2018 the `extern crate` declaration is not required and
|
||||
you can instead just `use` it:
|
||||
|
||||
```edition2018
|
||||
use core::any; // No extern crate required in Rust 2018.
|
||||
|
26
compiler/rustc_error_codes/src/error_codes/E0788.md
Normal file
26
compiler/rustc_error_codes/src/error_codes/E0788.md
Normal file
@ -0,0 +1,26 @@
|
||||
A `#[no_coverage]` attribute was applied to something which does not show up
|
||||
in code coverage, or is too granular to be excluded from the coverage report.
|
||||
|
||||
For now, this attribute can only be applied to function, method, and closure
|
||||
definitions. In the future, it may be added to statements, blocks, and
|
||||
expressions, and for the time being, using this attribute in those places
|
||||
will just emit an `unused_attributes` lint instead of this error.
|
||||
|
||||
Example of erroneous code:
|
||||
|
||||
```compile_fail,E0788
|
||||
#[no_coverage]
|
||||
struct Foo;
|
||||
|
||||
#[no_coverage]
|
||||
const FOO: Foo = Foo;
|
||||
```
|
||||
|
||||
`#[no_coverage]` tells the compiler to not generate coverage instrumentation for
|
||||
a piece of code when the `-C instrument-coverage` flag is passed. Things like
|
||||
structs and consts are not coverable code, and thus cannot do anything with this
|
||||
attribute.
|
||||
|
||||
If you wish to apply this attribute to all methods in an impl or module,
|
||||
manually annotate each method; it is not possible to annotate the entire impl
|
||||
with a `#[no_coverage]` attribute.
|
@ -3302,6 +3302,7 @@ pub enum Node<'hir> {
|
||||
Stmt(&'hir Stmt<'hir>),
|
||||
PathSegment(&'hir PathSegment<'hir>),
|
||||
Ty(&'hir Ty<'hir>),
|
||||
TypeBinding(&'hir TypeBinding<'hir>),
|
||||
TraitRef(&'hir TraitRef<'hir>),
|
||||
Binding(&'hir Pat<'hir>),
|
||||
Pat(&'hir Pat<'hir>),
|
||||
@ -3347,6 +3348,7 @@ impl<'hir> Node<'hir> {
|
||||
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
|
||||
Node::Lifetime(lt) => Some(lt.name.ident()),
|
||||
Node::GenericParam(p) => Some(p.name.ident()),
|
||||
Node::TypeBinding(b) => Some(b.ident),
|
||||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::Expr(..)
|
||||
|
@ -85,6 +85,7 @@ impl<'a> State<'a> {
|
||||
Node::Stmt(a) => self.print_stmt(&a),
|
||||
Node::PathSegment(a) => self.print_path_segment(&a),
|
||||
Node::Ty(a) => self.print_type(&a),
|
||||
Node::TypeBinding(a) => self.print_type_binding(&a),
|
||||
Node::TraitRef(a) => self.print_trait_ref(&a),
|
||||
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
|
||||
Node::Arm(a) => self.print_arm(&a),
|
||||
@ -1703,21 +1704,7 @@ impl<'a> State<'a> {
|
||||
|
||||
for binding in generic_args.bindings.iter() {
|
||||
start_or_comma(self);
|
||||
self.print_ident(binding.ident);
|
||||
self.print_generic_args(binding.gen_args, false, false);
|
||||
self.space();
|
||||
match generic_args.bindings[0].kind {
|
||||
hir::TypeBindingKind::Equality { ref term } => {
|
||||
self.word_space("=");
|
||||
match term {
|
||||
Term::Ty(ref ty) => self.print_type(ty),
|
||||
Term::Const(ref c) => self.print_anon_const(c),
|
||||
}
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
self.print_bounds(":", bounds);
|
||||
}
|
||||
}
|
||||
self.print_type_binding(binding);
|
||||
}
|
||||
|
||||
if !empty.get() {
|
||||
@ -1726,6 +1713,24 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
|
||||
self.print_ident(binding.ident);
|
||||
self.print_generic_args(binding.gen_args, false, false);
|
||||
self.space();
|
||||
match binding.kind {
|
||||
hir::TypeBindingKind::Equality { ref term } => {
|
||||
self.word_space("=");
|
||||
match term {
|
||||
Term::Ty(ref ty) => self.print_type(ty),
|
||||
Term::Const(ref c) => self.print_anon_const(c),
|
||||
}
|
||||
}
|
||||
hir::TypeBindingKind::Constraint { bounds } => {
|
||||
self.print_bounds(":", bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
|
@ -298,6 +298,7 @@ impl<'hir> Map<'hir> {
|
||||
Node::Stmt(_)
|
||||
| Node::PathSegment(_)
|
||||
| Node::Ty(_)
|
||||
| Node::TypeBinding(_)
|
||||
| Node::Infer(_)
|
||||
| Node::TraitRef(_)
|
||||
| Node::Pat(_)
|
||||
@ -323,7 +324,8 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
|
||||
pub fn get_parent_node(self, hir_id: HirId) -> HirId {
|
||||
self.find_parent_node(hir_id).unwrap()
|
||||
self.find_parent_node(hir_id)
|
||||
.unwrap_or_else(|| bug!("No parent for node {:?}", self.node_to_string(hir_id)))
|
||||
}
|
||||
|
||||
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
|
||||
@ -973,6 +975,7 @@ impl<'hir> Map<'hir> {
|
||||
.with_hi(seg.args.map_or_else(|| ident_span.hi(), |args| args.span_ext.hi()))
|
||||
}
|
||||
Node::Ty(ty) => ty.span,
|
||||
Node::TypeBinding(tb) => tb.span,
|
||||
Node::TraitRef(tr) => tr.path.span,
|
||||
Node::Binding(pat) => pat.span,
|
||||
Node::Pat(pat) => pat.span,
|
||||
@ -1205,6 +1208,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
|
||||
Some(Node::Stmt(_)) => node_str("stmt"),
|
||||
Some(Node::PathSegment(_)) => node_str("path segment"),
|
||||
Some(Node::Ty(_)) => node_str("type"),
|
||||
Some(Node::TypeBinding(_)) => node_str("type binding"),
|
||||
Some(Node::TraitRef(_)) => node_str("trait ref"),
|
||||
Some(Node::Binding(_)) => node_str("local"),
|
||||
Some(Node::Pat(_)) => node_str("pat"),
|
||||
|
@ -16,20 +16,6 @@ pub enum Region {
|
||||
Free(DefId, /* lifetime decl */ DefId),
|
||||
}
|
||||
|
||||
/// This is used in diagnostics to improve suggestions for missing generic arguments.
|
||||
/// It gives information on the type of lifetimes that are in scope for a particular `PathSegment`,
|
||||
/// so that we can e.g. suggest elided-lifetimes-in-paths of the form <'_, '_> e.g.
|
||||
#[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
|
||||
pub enum LifetimeScopeForPath {
|
||||
/// Contains all lifetime names that are in scope and could possibly be used in generics
|
||||
/// arguments of path.
|
||||
NonElided(Vec<LocalDefId>),
|
||||
|
||||
/// Information that allows us to suggest args of the form `<'_>` in case
|
||||
/// no generic arguments were provided for a path.
|
||||
Elided,
|
||||
}
|
||||
|
||||
/// A set containing, at most, one known element.
|
||||
/// If two distinct values are inserted into a set, then it
|
||||
/// becomes `Many`, which can be used to detect ambiguities.
|
||||
|
@ -1599,11 +1599,6 @@ rustc_queries! {
|
||||
desc { "looking up late bound vars" }
|
||||
}
|
||||
|
||||
query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
|
||||
storage(ArenaCacheSelector<'tcx>)
|
||||
desc { "finds the lifetime scope for an HirId of a PathSegment" }
|
||||
}
|
||||
|
||||
query visibility(def_id: DefId) -> ty::Visibility {
|
||||
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
|
||||
separate_provide_extern
|
||||
|
@ -6,7 +6,7 @@ use crate::hir::place::Place as HirPlace;
|
||||
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
||||
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
|
||||
use crate::middle::resolve_lifetime;
|
||||
use crate::middle::stability;
|
||||
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
|
||||
use crate::mir::{
|
||||
@ -2821,10 +2821,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> {
|
||||
self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id))
|
||||
}
|
||||
|
||||
/// Whether the `def_id` counts as const fn in the current crate, considering all active
|
||||
/// feature gates
|
||||
pub fn is_const_fn(self, def_id: DefId) -> bool {
|
||||
|
@ -6,9 +6,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||
use crate::middle::lib_features::LibFeatures;
|
||||
use crate::middle::privacy::AccessLevels;
|
||||
use crate::middle::resolve_lifetime::{
|
||||
LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
|
||||
};
|
||||
use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
|
||||
use crate::middle::stability::{self, DeprecationEntry};
|
||||
use crate::mir;
|
||||
use crate::mir::interpret::GlobalId;
|
||||
|
@ -77,6 +77,7 @@ impl CheckAttrVisitor<'_> {
|
||||
for attr in attrs {
|
||||
let attr_is_valid = match attr.name_or_empty() {
|
||||
sym::inline => self.check_inline(hir_id, attr, span, target),
|
||||
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
|
||||
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
|
||||
sym::marker => self.check_marker(hir_id, attr, span, target),
|
||||
sym::rustc_must_implement_one_of => {
|
||||
@ -291,6 +292,57 @@ impl CheckAttrVisitor<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a `#[no_coverage]` is applied directly to a function
|
||||
fn check_no_coverage(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr: &Attribute,
|
||||
span: Span,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
match target {
|
||||
// no_coverage on function is fine
|
||||
Target::Fn
|
||||
| Target::Closure
|
||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
|
||||
|
||||
// function prototypes can't be covered
|
||||
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` is ignored on function prototypes").emit();
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
Target::Mod | Target::ForeignMod | Target::Impl | Target::Trait => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` does not propagate into items and must be applied to the contained functions directly").emit();
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
Target::Expression | Target::Statement | Target::Arm => {
|
||||
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||
lint.build("`#[no_coverage]` may only be applied to function definitions")
|
||||
.emit();
|
||||
});
|
||||
true
|
||||
}
|
||||
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
attr.span,
|
||||
E0788,
|
||||
"`#[no_coverage]` must be applied to coverable code",
|
||||
)
|
||||
.span_label(span, "not coverable code")
|
||||
.emit();
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_generic_attr(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
|
@ -8,12 +8,11 @@
|
||||
|
||||
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||
use rustc_hir::hir_id::ItemLocalId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node};
|
||||
use rustc_hir::{GenericParamKind, HirIdMap};
|
||||
@ -141,9 +140,6 @@ struct NamedRegionMap {
|
||||
// - trait refs
|
||||
// - bound types (like `T` in `for<'a> T<'a>: Foo`)
|
||||
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
|
||||
|
||||
// maps `PathSegment` `HirId`s to lifetime scopes.
|
||||
scope_for_path: Option<FxHashMap<LocalDefId, FxHashMap<ItemLocalId, LifetimeScopeForPath>>>,
|
||||
}
|
||||
|
||||
pub(crate) struct LifetimeContext<'a, 'tcx> {
|
||||
@ -362,10 +358,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||
_ => None,
|
||||
},
|
||||
late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
|
||||
lifetime_scope_map: |tcx, id| {
|
||||
let item_id = item_for(tcx, id);
|
||||
do_resolve(tcx, item_id, false, true).scope_for_path.unwrap().remove(&id)
|
||||
},
|
||||
|
||||
..*providers
|
||||
};
|
||||
@ -406,7 +398,7 @@ fn resolve_lifetimes_trait_definition(
|
||||
tcx: TyCtxt<'_>,
|
||||
local_def_id: LocalDefId,
|
||||
) -> ResolveLifetimes {
|
||||
convert_named_region_map(do_resolve(tcx, local_def_id, true, false))
|
||||
convert_named_region_map(do_resolve(tcx, local_def_id, true))
|
||||
}
|
||||
|
||||
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
|
||||
@ -414,21 +406,17 @@ fn resolve_lifetimes_trait_definition(
|
||||
/// `named_region_map`, `is_late_bound_map`, etc.
|
||||
#[tracing::instrument(level = "debug", skip(tcx))]
|
||||
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes {
|
||||
convert_named_region_map(do_resolve(tcx, local_def_id, false, false))
|
||||
convert_named_region_map(do_resolve(tcx, local_def_id, false))
|
||||
}
|
||||
|
||||
fn do_resolve(
|
||||
tcx: TyCtxt<'_>,
|
||||
local_def_id: LocalDefId,
|
||||
trait_definition_only: bool,
|
||||
with_scope_for_path: bool,
|
||||
) -> NamedRegionMap {
|
||||
let item = tcx.hir().expect_item(local_def_id);
|
||||
let mut named_region_map = NamedRegionMap {
|
||||
defs: Default::default(),
|
||||
late_bound_vars: Default::default(),
|
||||
scope_for_path: with_scope_for_path.then(|| Default::default()),
|
||||
};
|
||||
let mut named_region_map =
|
||||
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
|
||||
let mut visitor = LifetimeContext {
|
||||
tcx,
|
||||
map: &mut named_region_map,
|
||||
@ -524,38 +512,6 @@ fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug")]
|
||||
fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath {
|
||||
let mut available_lifetimes = vec![];
|
||||
loop {
|
||||
match scope {
|
||||
Scope::Binder { lifetimes, s, .. } => {
|
||||
available_lifetimes.extend(lifetimes.keys());
|
||||
scope = s;
|
||||
}
|
||||
Scope::Body { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
Scope::Elision { elide, s } => {
|
||||
if let Elide::Exact(_) = elide {
|
||||
return LifetimeScopeForPath::Elided;
|
||||
} else {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
Scope::ObjectLifetimeDefault { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
Scope::Root => {
|
||||
return LifetimeScopeForPath::NonElided(available_lifetimes);
|
||||
}
|
||||
Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => {
|
||||
scope = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
/// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
|
||||
fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
|
||||
@ -1202,53 +1158,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assoc_type_binding(&mut self, type_binding: &'tcx hir::TypeBinding<'_>) {
|
||||
let scope = self.scope;
|
||||
if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
|
||||
// We add lifetime scope information for `Ident`s in associated type bindings and use
|
||||
// the `HirId` of the type binding as the key in `LifetimeMap`
|
||||
let lifetime_scope = get_lifetime_scopes_for_path(scope);
|
||||
let map = scope_for_path.entry(type_binding.hir_id.owner).or_default();
|
||||
map.insert(type_binding.hir_id.local_id, lifetime_scope);
|
||||
}
|
||||
hir::intravisit::walk_assoc_type_binding(self, type_binding);
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
let depth = path.segments.len() - i - 1;
|
||||
if let Some(ref args) = segment.args {
|
||||
self.visit_segment_args(path.res, depth, args);
|
||||
}
|
||||
|
||||
let scope = self.scope;
|
||||
if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
|
||||
// Add lifetime scope information to path segment. Note we cannot call `visit_path_segment`
|
||||
// here because that call would yield to resolution problems due to `walk_path_segment`
|
||||
// being called, which processes the path segments generic args, which we have already
|
||||
// processed using `visit_segment_args`.
|
||||
let lifetime_scope = get_lifetime_scopes_for_path(scope);
|
||||
if let Some(hir_id) = segment.hir_id {
|
||||
let map = scope_for_path.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, lifetime_scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx hir::PathSegment<'tcx>) {
|
||||
let scope = self.scope;
|
||||
if let Some(scope_for_path) = self.map.scope_for_path.as_mut() {
|
||||
let lifetime_scope = get_lifetime_scopes_for_path(scope);
|
||||
if let Some(hir_id) = path_segment.hir_id {
|
||||
let map = scope_for_path.entry(hir_id.owner).or_default();
|
||||
map.insert(hir_id.local_id, lifetime_scope);
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_path_segment(self, path_span, path_segment);
|
||||
}
|
||||
|
||||
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
|
||||
let output = match fd.output {
|
||||
hir::FnRetTy::DefaultReturn(_) => None,
|
||||
@ -2227,6 +2145,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
|
||||
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
|
||||
Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => None,
|
||||
|
||||
Node::TypeBinding(_) if let Node::TraitRef(_) = self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)) => None,
|
||||
|
||||
// Everything else (only closures?) doesn't
|
||||
// actually enjoy elision in return types.
|
||||
_ => {
|
||||
@ -2548,16 +2469,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
// If we specifically need the `scope_for_path` map, then we're in the
|
||||
// diagnostic pass and we don't want to emit more errors.
|
||||
if self.map.scope_for_path.is_some() {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
rustc_span::DUMMY_SP,
|
||||
"Encountered unexpected errors during diagnostics related part",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
|
||||
spans.sort();
|
||||
let mut spans_dedup = spans.clone();
|
||||
|
@ -249,6 +249,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
|
||||
| hir::Node::Stmt(..)
|
||||
| hir::Node::PathSegment(..)
|
||||
| hir::Node::Ty(..)
|
||||
| hir::Node::TypeBinding(..)
|
||||
| hir::Node::TraitRef(..)
|
||||
| hir::Node::Binding(..)
|
||||
| hir::Node::Pat(..)
|
||||
|
@ -450,21 +450,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
||||
.discr_type()
|
||||
.to_ty(tcx),
|
||||
|
||||
Node::TraitRef(trait_ref @ &TraitRef {
|
||||
path, ..
|
||||
}) if let Some((binding, seg)) =
|
||||
path
|
||||
.segments
|
||||
.iter()
|
||||
.find_map(|seg| {
|
||||
seg.args?.bindings
|
||||
.iter()
|
||||
.find_map(|binding| if binding.opt_const()?.hir_id == hir_id {
|
||||
Some((binding, seg))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}) =>
|
||||
Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
|
||||
if let Node::TraitRef(trait_ref) = tcx.hir().get(
|
||||
tcx.hir().get_parent_node(binding_id)
|
||||
) =>
|
||||
{
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
|
||||
|
@ -5,7 +5,6 @@ use rustc_errors::{
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::hir::map::fn_sig;
|
||||
use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
|
||||
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::def_id::DefId;
|
||||
@ -291,7 +290,69 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// Creates lifetime name suggestions from the lifetime parameter names
|
||||
fn get_lifetime_args_suggestions_from_param_names(&self, num_params_to_take: usize) -> String {
|
||||
fn get_lifetime_args_suggestions_from_param_names(
|
||||
&self,
|
||||
path_hir_id: Option<hir::HirId>,
|
||||
num_params_to_take: usize,
|
||||
) -> String {
|
||||
debug!(?path_hir_id);
|
||||
|
||||
if let Some(path_hir_id) = path_hir_id {
|
||||
let mut ret = Vec::new();
|
||||
for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
|
||||
debug!(?id);
|
||||
let params = if let Some(generics) = node.generics() {
|
||||
generics.params
|
||||
} else if let hir::Node::Ty(ty) = node
|
||||
&& let hir::TyKind::BareFn(bare_fn) = ty.kind
|
||||
{
|
||||
bare_fn.generic_params
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
ret.extend(params.iter().filter_map(|p| {
|
||||
let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
|
||||
= p.kind
|
||||
else { return None };
|
||||
let hir::ParamName::Plain(name) = p.name else { return None };
|
||||
Some(name.to_string())
|
||||
}));
|
||||
// Suggest `'static` when in const/static item-like.
|
||||
if let hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Const { .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Const { .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::ForeignItem(hir::ForeignItem {
|
||||
kind: hir::ForeignItemKind::Static { .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::AnonConst(..) = node
|
||||
{
|
||||
ret.extend(
|
||||
std::iter::repeat("'static".to_owned())
|
||||
.take(num_params_to_take.saturating_sub(ret.len())),
|
||||
);
|
||||
}
|
||||
if ret.len() >= num_params_to_take {
|
||||
return ret[..num_params_to_take].join(", ");
|
||||
}
|
||||
// We cannot refer to lifetimes defined in an outer function.
|
||||
if let hir::Node::Item(_) = node {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We could not gather enough lifetime parameters in the scope.
|
||||
// We use the parameter names from the target type's definition instead.
|
||||
self.gen_params
|
||||
.params
|
||||
.iter()
|
||||
@ -501,44 +562,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
let num_params_to_take = num_missing_args;
|
||||
let msg = format!("add missing {} argument{}", self.kind(), pluralize!(num_missing_args));
|
||||
|
||||
// we first try to get lifetime name suggestions from scope or elision information. If none is
|
||||
// available we use the parameter definitions
|
||||
let suggested_args = if let Some(hir_id) = self.path_segment.hir_id {
|
||||
if let Some(lifetimes_in_scope) = self.tcx.lifetime_scope(hir_id) {
|
||||
match lifetimes_in_scope {
|
||||
LifetimeScopeForPath::NonElided(param_names) => {
|
||||
debug!("NonElided(param_names: {:?})", param_names);
|
||||
|
||||
if param_names.len() >= num_params_to_take {
|
||||
// use lifetime parameters in scope for suggestions
|
||||
param_names
|
||||
.iter()
|
||||
.take(num_params_to_take)
|
||||
.map(|def_id| {
|
||||
self.tcx.item_name(def_id.to_def_id()).to_ident_string()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
} else {
|
||||
// Not enough lifetime arguments in scope -> create suggestions from
|
||||
// lifetime parameter names in definition. An error for the incorrect
|
||||
// lifetime scope will be output later.
|
||||
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
|
||||
}
|
||||
}
|
||||
LifetimeScopeForPath::Elided => {
|
||||
debug!("Elided");
|
||||
// use suggestions of the form `<'_, '_>` in case lifetime can be elided
|
||||
["'_"].repeat(num_params_to_take).join(",")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
|
||||
}
|
||||
} else {
|
||||
self.get_lifetime_args_suggestions_from_param_names(num_params_to_take)
|
||||
};
|
||||
|
||||
let suggested_args = self.get_lifetime_args_suggestions_from_param_names(
|
||||
self.path_segment.hir_id,
|
||||
num_params_to_take,
|
||||
);
|
||||
debug!("suggested_args: {:?}", &suggested_args);
|
||||
|
||||
match self.angle_brackets {
|
||||
|
@ -11,7 +11,7 @@ LL | type Assoc<'a> where Self: 'a;
|
||||
| ^^^^^ --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | fn g(&self) -> Self::Assoc<'_>;
|
||||
LL | fn g(&self) -> Self::Assoc<'a>;
|
||||
| ~~~~~~~~~
|
||||
|
||||
error[E0107]: missing generics for associated type `Trait::Assoc`
|
||||
@ -27,7 +27,7 @@ LL | type Assoc<'a> where Self: 'a;
|
||||
| ^^^^^ --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | fn g(&self) -> Self::Assoc<'_> {
|
||||
LL | fn g(&self) -> Self::Assoc<'a> {
|
||||
| ~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -11,7 +11,7 @@ LL | type Item<'a>;
|
||||
| ^^^^ --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | fn next(&mut self) -> Option<Self::Item<'_>>;
|
||||
LL | fn next(&mut self) -> Option<Self::Item<'a>>;
|
||||
| ~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
|
55
src/test/ui/lint/no-coverage.rs
Normal file
55
src/test/ui/lint/no-coverage.rs
Normal file
@ -0,0 +1,55 @@
|
||||
#![feature(extern_types)]
|
||||
#![feature(no_coverage)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![warn(unused_attributes)]
|
||||
#![no_coverage]
|
||||
//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
|
||||
#[no_coverage]
|
||||
//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
trait Trait {
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
const X: u32;
|
||||
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
type T;
|
||||
|
||||
type U;
|
||||
}
|
||||
|
||||
#[no_coverage]
|
||||
//~^ WARN: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
impl Trait for () {
|
||||
const X: u32 = 0;
|
||||
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
type T = Self;
|
||||
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
type U = impl Trait; //~ ERROR unconstrained opaque type
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
static X: u32;
|
||||
|
||||
#[no_coverage] //~ ERROR `#[no_coverage]` must be applied to coverable code
|
||||
type T;
|
||||
}
|
||||
|
||||
#[no_coverage]
|
||||
fn main() {
|
||||
#[no_coverage]
|
||||
//~^ WARN `#[no_coverage]` may only be applied to function definitions
|
||||
let _ = ();
|
||||
|
||||
match () {
|
||||
#[no_coverage]
|
||||
//~^ WARN `#[no_coverage]` may only be applied to function definitions
|
||||
() => (),
|
||||
}
|
||||
|
||||
#[no_coverage]
|
||||
//~^ WARN `#[no_coverage]` may only be applied to function definitions
|
||||
return ();
|
||||
}
|
101
src/test/ui/lint/no-coverage.stderr
Normal file
101
src/test/ui/lint/no-coverage.stderr
Normal file
@ -0,0 +1,101 @@
|
||||
warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
--> $DIR/no-coverage.rs:8:1
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/no-coverage.rs:4:9
|
||||
|
|
||||
LL | #![warn(unused_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
--> $DIR/no-coverage.rs:20:1
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
warning: `#[no_coverage]` may only be applied to function definitions
|
||||
--> $DIR/no-coverage.rs:42:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
warning: `#[no_coverage]` may only be applied to function definitions
|
||||
--> $DIR/no-coverage.rs:47:9
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
warning: `#[no_coverage]` may only be applied to function definitions
|
||||
--> $DIR/no-coverage.rs:52:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:11:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | const X: u32;
|
||||
| ------------- not coverable code
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:14:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | type T;
|
||||
| ------- not coverable code
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:25:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | type T = Self;
|
||||
| -------------- not coverable code
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:28:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | type U = impl Trait;
|
||||
| -------------------- not coverable code
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:33:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | static X: u32;
|
||||
| -------------- not coverable code
|
||||
|
||||
error[E0788]: `#[no_coverage]` must be applied to coverable code
|
||||
--> $DIR/no-coverage.rs:36:5
|
||||
|
|
||||
LL | #[no_coverage]
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | type T;
|
||||
| ------- not coverable code
|
||||
|
||||
warning: `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
|
||||
--> $DIR/no-coverage.rs:5:1
|
||||
|
|
||||
LL | #![no_coverage]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: unconstrained opaque type
|
||||
--> $DIR/no-coverage.rs:29:14
|
||||
|
|
||||
LL | type U = impl Trait;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `U` must be used in combination with a concrete type within the same module
|
||||
|
||||
error: aborting due to 7 previous errors; 6 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0788`.
|
@ -171,8 +171,8 @@ LL | pub union Qux<'t, 'k, I> {
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++
|
||||
|
||||
error[E0107]: this union takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:43:44
|
||||
@ -243,8 +243,8 @@ LL | pub union Qux<'t, 'k, I> {
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++
|
||||
|
||||
error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:45
|
||||
@ -261,8 +261,8 @@ LL | trait Tar<'t, 'k, I> {}
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-specifier.rs:51:44
|
||||
@ -360,8 +360,8 @@ LL | trait Tar<'t, 'k, I> {}
|
||||
| ^^^ -- --
|
||||
help: add missing lifetime argument
|
||||
|
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, '_, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| ++++
|
||||
LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user